天天看點

Swift學習總結【持續更新】

1、 try、try?、try!的差別:
  • try:需要用catch捕捉異常,如:
do {
         let data = try encoder.encode(item)		
         try data.write(to: dataFilePath(), options: .atomic)
     } catch {
         print("Error encoding item array:\(error.localizedDescription)")
     }
           
  • try? :傳回一個可選值類型,如果出現異常,傳回nil.如果沒有異常,則傳回可選值。(如果不想處理異常那麼可以用這個關鍵字),如:
let data = try? encoder.encode(item)
try? data!.write(to: dataFilePath(), options: .atomic)
           

(因為使用try?是以data為可選類型,使用前需unwrap)

  • try! : 抛出了異常後,程式會立刻停止(如果不想處理異常,而且不想讓異常繼續傳播下去,類似NSAssert().), 如:
let data = try! encoder.encode(item)
try! data.write(to: dataFilePath(), options: .atomic)
           
2、 PropertyListEncoder、NSKeyedArchiver、NSUserDefault
  • PropertyListEncoder

    使用 PropertyListEncoder可以對遵循Codable協定的類進行歸檔

    将包含自定義類HighScoreItem的數組進行歸檔:

static func saveHighScore(_ item:[HighScoreItem]){
    let encoder = PropertyListEncoder()
    do {
        let data = try encoder.encode(item)
        try data.write(to: dataFilePath(), options: .atomic)
    } catch {
        print("Error encoding item array:\(error.localizedDescription)")
    }
}
           

解檔:

static func loadHighScores() -> [HighScoreItem]{
    var items = [HighScoreItem]()
    let path = dataFilePath()
    if let data = try? Data(contentsOf: path){
        let decoder = PropertyListDecoder()
        do{
            items = try decoder.decode([HighScoreItem].self, from: data)
        }catch{
            print("Error decoding item array:\(error .localizedDescription)")
        }
    }
    return items
}
           
  • NSKeyedArchiver

    NSKeyedArchiver可以将遵守NSCoding協定的Cocoa類進行歸檔,将資料轉換為 Data 類型,然後再存儲到UserDefaults或寫到檔案:

do {
    let data = try NSKeyedArchiver.archivedData(withRootObject: item, requiringSecureCoding: true)
    try data.write(to: dataFilePath(), options: .atomic)
} catch  {
    print("Error encoding item array:\(error.localizedDescription)")
}
           
  • NSUserDefault

    适合存儲資料量較少的資料

let defaults = UserDefaults.standard
defaults.set(item, forKey: "item");
           
3、NSArry和Array

Array是Swift中的結構體類型(struct), 屬于是值類型.

NSArray是OC中的對象類型, 屬于引用類型.

var aarr = ["happy", "every", "day"]
    var barr : NSMutableArray = ["happy", "every", "day"]
    
    //1
    aarr[2] = "minute" //直接改變了aarr第二個元素的值
    barr[2] = "minute" //讓barr第二個元素指向"minute"
    print("1---\(aarr)")
    print("1---\(barr)")
    /*輸出:
        1---["happy", "every", "minute"]
        1---(
        happy,
        every,
        minute
        )
    */
    
    //2
    func changeA (var a:Array<String>) {
        a[2] = "second" //a是對aarr的拷貝
    }
    func changeB (a : NSMutableArray) {
        a[2] = "second" //a是對barr的引用
    }
    changeA(aarr) //值類型指派時進行拷貝, 改變是a[2]的值, aarr并沒有影響
    changeB(barr) //引用類型指派時傳遞的是引用, a[2]和barr[2]都指向同一個位址.
    print("2---\(aarr)")
    print("2---\(barr)")
    /*輸出:
        2---["happy", "every", "minute"]
        2---(
        happy,
        every,
        second
        )
    */
           

代碼來自HWenj的文章《Swift中Array和OC中的NSArray》

4、weak和unowned差別
  • unowned辨別的變量不能是可選類型(Optional),不能指向nil,必須在 init 方法中初始化值。
  • weak辨別的變量可以為可選類型,可以指向nil。

    參考:糾結的哈士奇的文章

5、oc和swift中==的差別

如果比較的是類(引用類型)

  • 在Objective-C 中,隻有兩個對象指向的記憶體位址一樣才為true
  • 在Swift中,對比的是對象的值,跟記憶體位址無關(如果要對比記憶體位址使用===)
6、方法的參數

一般方法會有一個或多個參數,每個參數會有兩個名字,外部參數名(external label)和内部參數名(internal label),例如:

func downloadImage(for searchResult: SearchResult,  
                withTimeout timeout: TimeInterval, 
                  andPlaceOn button: UIButton) {
  . . .
}
           

這個方法有3個參數searchResult、timeout、button,這些是内部參數名,可以在方法内使用。

而外部參數名是方法名的一部分,即以上方法名為:downloadImage(for:withTimeout:andPlaceOn:)

調用方法時,寫法為:

downloadImage(for: result, withTimeout: 10, 
                            andPlaceOn: imageButton)
           

有些方法第一個外部參數名會以下劃線“_”代替,進而忽略外部參數名,如:

override func tableView(_ tableView: UITableView, 
      numberOfRowsInSection section: Int) -> Int
           

這些方法一般都是來源于過去Objective-C的寫法,已經把首個外部參數名合并在方法名之中。

7、switch技巧

可以通過"…<"比對範圍。如:

switch difference {
  case 0:
    title = "Perfect!"
  case 1..<5:
    title = "You almost had it!"
  case 5..<10:
    title = "Pretty good!"
  default:
    title = "Not even close..."
}
           

8、for循環技巧

循環周遊數組時,我們這樣寫:

for item in items {
  if !item.checked {
    count += 1
  }
}
           

可以在後面加上條件選擇

for item in items where !item.checked {
  count += 1
}
           

如果我們想要循環n次,可以這樣寫:

for i in 0...4 {   // or 0..<5
  print(i)
}
           

也可以通過stride方法:

for i in stride(from: 0, to: 5, by: 1) {
  print(i)
}
           

stride()方法建立了代表從0到5,增長間隔是1的對象。如果想輸出從0到5的偶數,則把最後一個參數改為2,如果想要倒數,最後的參數傳入負值即可。

9、通過filter篩選

如果要篩選出數組中,符合某一條件的對象。如篩選出items數組中,屬性checked為false的對象,可以用filter方法

10、存儲屬性(Stored property)vc計算屬性(Computed property)

  • 存儲屬性:常見的執行個體變量和常量
  • 計算屬性:不存儲資料,在讀和寫時會執行邏輯代碼,如:
var indexOfSelectedChecklist: Int {
  get {
    return UserDefaults.standard.integer(
                forKey: "ChecklistIndex")
  }
  set {
    UserDefaults.standard.set(newValue, 
                                forKey: "ChecklistIndex")
  }
}
           

11、類中的方法

類的方法有三種:

  • 執行個體方法:需要先建立執行個體,才能調用,如:
let myInstance = MyObject()   // create the object instance
. . .
myInstance.doSomething()      // call the method”
           
  • 類方法:不需要建立執行個體,直接由類調用,常用做工廠方法來建立執行個體,如:
class MyObject {
  . . .

  class func makeObject(text: String) -> MyObject {
    let m = MyObject()
    m.text = text
    return m
  }
}

let myInstance = MyObject.makeObject(text: "Hello world")
           
  • 初始化方法:除了上面的工廠方法,也可以使用自定義的初始化方法,用于建立和初始化執行個體。在初始化方法中,執行個體變量和常量必須被指派(Swfit要求在初始化方法執行完之後,變量和常量除非是可選類型,否則必須被指派),如:
class MyObject {
  . . .

  init(text: String) {
    self.text = text
  }
}

let myInstance = MyObject(text: "Hello world")
           

一個類的初始化方法可以有多個,如UITableViewController有init?(coder:)、init(nibName:bundle:)、init(style:) 等多個初始化方法。

12、if判斷技巧

如果我們要用if判斷多個條件,在Objective-C中可以用“&”進行連接配接,而在Swift中可以使用“,”進行連接配接,如:

if error == nil, let p = placemarks, !p.isEmpty {
  self.placemark = p.last!
} else {
  self.placemark = nil
} 
           

隻有error為nil、p不為nil、p數組不為空(placemarks為數組)三個條件同時為真,if判斷才為真。

13、 as、as?、as!的差別:

【先下班】