## 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".
~~~