## OPTIONALS
Apple 在 Swift 中為其加入了 Optional,Optional 是一種類型,可以有值,也可以等于 nil(也就是沒有值)。在 oc 中,只有指向對象的指針可以為 nil,而在 swift 中基本類型創建后沒有初始值,而是為 nil,并且無法使用。
開發中遇到的一些意想不到的問題,例如程序崩潰、影響UI,最常見的原因就是因為使用了為 nil 的值,Optional 這一特性確保了代碼安全性。
* 定義一個 Optional 的值只需在類型后添加一個問號“?”:
~~~
var str: String? //輸出nil
//以上是一個名為 str 的 Optional String.
~~~
* Optional 類型無法直接使用,需要拆包(unwrap)后取出原類型的值后使用。在 Optional 類型后加上感嘆號(!)進行顯式拆包(Force unwrapping optionals):
~~~
var str: String? = "Hallo World"
str //nil
str! //"Hallo World"
print(str) //輸出"Optional("Hallo World")"
print(str!) //輸出"Hallo World"
~~~
* 通過 if let 語句可以判斷 Optional 是否有值,如果有,將其拆包賦值給一個本地變量:
~~~
func getHaterStatus(weather: String) -> String? {
if weather == "sunny" {
return nil
} else {
return "Hate"
}
//該方法返回一個 Optional String 類型
}
func takeHaterAction(status: String) {
if status == "Hate" {
print("Hating")
}
//該方法需要傳入一個 String 類型
}
if let status = getHaterStatus("rainy") {
takeHaterAction(status)
/* if let 語句將調用了 getHaterStatus 方法后得到的 Optional 值拆包后賦值給本地變量 status,確保 takeHaterAction 方法傳入的是一個有值的參數。 */
}
~~~
* Optional 還提供了隱式拆包(implicitly unwrapped optionals),隱式拆包的 Optional 在使用前無需拆包。要使用隱式拆包需要在變量聲明時的數據類型后加上感嘆號(!):
~~~
var str: String! = "Hello World!"
str //Hello World!
~~~
使用隱式拆包需要小心,要確保變量已被正確初始化。一般會在以下情況遇到 Implicitly unwrapped:
1. 當使用 Apple 的 API 時會經常碰到隱式拆包的返回值。
2. 當使用 UIKit 的用戶界面元素時。
### 總結一下 Optional:
* 一個普通類型的變量必須有值,比如一個 String 變量需要擁有一個 string,哪怕是空的字符串("“)。
* 一個 Optional 類型的變量可以有值也可以無值(也就是為nil),但在使用前必須將其拆包(Unwrap)。
* 一個隱式拆包的 Optional 類型變量可以有值也可以無值,使用前不需要拆包,因此 Swift 也不會為你檢查,需要格外小心。
* * *
* Optional Chaining: 在 Objective-C 中,對 nil 發送消息會得到 nil,但是在 Swift 中不允許這么做。當對一個 Optional 類型的對象發送消息時,通過 Optional Chaining 可以對其判斷是否有值,如果是則發送消息,反之則什么也不做:
~~~
func albumReleasedYear(year: Int) -> String? {
switch year {
case 2006: return "Taylor Swift"
case 2008: return "Fearless"
case 2010: return "Speak Now"
case 2012: return "Red"
case 2014: return "1989"
default: return nil
}
}
let album = albumReleasedYear(2006)?.uppercaseString //輸出 Optional("TAYLOR SWFIT")
//即問號(?)前有值才發送消息,這就是 Optional Chaining
Optional Chaining 如同其名可以像鏈條一樣連接,多長都可以,Swift 會從左至右檢查直至發現 nil 即終止:
let album = albumReleasedYear(2006)?.someOptionalValue?.someOtherOptionalValue?.whatever
~~~
* The nil coalescing operator: Swift 的這個特性可以讓你的代碼更加簡單和安全。例如:當 Value A 有值時則使用 Value A,如果 Value A 無值,則使用 Value B,這對 Optional 十分有用:
~~~
let album = albumReleasedYear(2006) ?? "unknown"
print("The album is \(album)")
//如果 albumReleasedYear(2006)返回的 Optional 無值,則使用非 Optional "unknown".
~~~