在 C 和 Objective-C 中,沒(méi)有可選項(xiàng)的概念。在 Objective-C 中有一個(gè)近似的特性,一個(gè)方法可以返回一個(gè)對(duì)象或者返回 nil 。 nil 的意思是“缺少一個(gè)可用對(duì)象”。然而,他只能用在對(duì)象上,卻不能作用在結(jié)構(gòu)體,基礎(chǔ)的 C 類型和枚舉值上。對(duì)于這些類型,Objective-C 會(huì)返回一個(gè)特殊的值(例如 NSNotFound )來(lái)表示值的缺失。這種方法是建立在假設(shè)調(diào)用者知道這個(gè)特殊的值并記得去檢查他。然而,Swift 中的可選項(xiàng)就可以讓你知道任何類型的值的缺失,他并不需要一個(gè)特殊的值,它強(qiáng)調(diào)的是有沒(méi)有,而非空不空。
可以利用可選項(xiàng)來(lái)處理值可能缺失的情況??蛇x項(xiàng)意味著:這里有一個(gè)值,他等于x或者根本沒(méi)有值
swift里面常量/變量的聲明方式:
| 聲明常量 let | 聲明變量 var |
|---|---|
1? let name = "swift"或let name: String = "swift"
|
6? var name = "swift"或var name: String = "swift"
|
2? let name: String
|
7? var name: String
|
3?let name: String?(或!) = "swift"
|
8? var name: String?(或!) = "swift"
|
4? let name: String?
|
9? var name: String?
|
5? let name: String!
|
10 var name: String!
|
普通類型
常量/變量聲明的時(shí)候類型后面不帶有?或者!為普通類型,也就是上表中1?, 2?, 6?,7?聲明方式
- 要么在聲明的時(shí)候賦初始值,要么在其所屬類的初始化方法中賦初始值,才能參與運(yùn)算
- 這種類型沒(méi)有默認(rèn)初始值,且生命周期中不能接收nil
可選項(xiàng)(Optional Type)
常量/變量聲明的時(shí)候類型后面帶有?或者!為可選類型(optional type,即可選項(xiàng)),也就是上表中3?,4?,5?,8?,9?,10聲明方式。
此外let name: Optinal<String> 的簡(jiǎn)寫形式是4?,二者作用跟和用法是完全一樣的; 同理let name: ImplicitlyUnwrappedOptional<String>的簡(jiǎn)寫形式是5?,二者作用跟和用法也是完全一樣。
- 聲明為Optional常量時(shí)如果沒(méi)有賦初始值,此常量沒(méi)有默認(rèn)值,需要在構(gòu)造函數(shù)中給常量設(shè)置初始數(shù)值
- 聲明為Optional的變量,如果不顯式的賦值就會(huì)有個(gè)默認(rèn)值nil
- 聲明為Optional的變量/常量不能直接參與運(yùn)算,必須解包后才能參與運(yùn)算
- 解包后的Optional變量/常量如果沒(méi)有值(為nil)參與運(yùn)算也會(huì)發(fā)生Crash
我們可以對(duì)一個(gè)可選項(xiàng)類型(Optional Type)使用后綴操作符!來(lái)強(qiáng)制拆包(force unwrap)訪問(wèn)這個(gè)值,來(lái)繼續(xù)后面的操作。
可選類型類似于Objective-C中指針的nil值,但是nil只對(duì)類(class)有用,而swift中可選類型對(duì)所有的類型都可用,并且更安全。
強(qiáng)制展開
如果一個(gè)可選有值,它“不等于” nil ,可以通過(guò)比較 nil 來(lái)判斷一個(gè)可選中是否包含值。
一旦你確定可選中包含值,可以使用后綴操作符!來(lái)強(qiáng)制拆包(force unwrap)訪問(wèn)這個(gè)值,,感嘆號(hào)的意思就是說(shuō)“我知道這個(gè)可選項(xiàng)里邊有值,展開吧?!边@就是所謂的可選值的強(qiáng)制展開。
var myString:String?
myString = "Hello, Swift!"
if myString != nil {
print(myString) //prints:Optional("Hello, Swift!")
// 強(qiáng)制展開
print(myString!) //prints:Hello, Swift!
}else{
print("myString 值為 nil")
}
注意:
使用 ! 來(lái)獲取一個(gè)不存在的可選值會(huì)導(dǎo)致carsh,在使用!強(qiáng)制展開之前必須確??蛇x項(xiàng)中包含一個(gè)非 nil 的值。
可選項(xiàng)綁定
可以使用可選項(xiàng)綁定來(lái)判斷可選項(xiàng)是否包含值,如果包含就把值賦給一個(gè)臨時(shí)的常量/變量??蛇x綁定可以與 if 和 while 的語(yǔ)句使用來(lái)檢查可選項(xiàng)內(nèi)部的值,并賦值給一個(gè)變量或常量。
var myString:String?
myString = "Hello, Swift!"
if let yourString = myString {
print("你的字符串值為 - \(yourString)")
}else{
print("你的字符串沒(méi)有值")
}
//prints:你的字符串值為 - Hello, Swift!
隱式展開
有時(shí)在一些程序結(jié)構(gòu)中可選項(xiàng)一旦被設(shè)定值之后,就會(huì)一直擁有值。在這種情況下,就可以去掉檢查的需求,不必每次訪問(wèn)的時(shí)候都進(jìn)行展開,因?yàn)樗梢园踩拇_認(rèn)每次訪問(wèn)的時(shí)候都有一個(gè)值。這種類型的可選項(xiàng)被定義為隱式展開可選項(xiàng)。
通過(guò)在類型后邊添加一個(gè)嘆號(hào)( String! )而非問(wèn)號(hào)( String? ) 來(lái)聲明一個(gè)隱式展開可選項(xiàng)。
在可選項(xiàng)被定義的時(shí)候就能立即確認(rèn)其中有值的情況下,隱式展開可選項(xiàng)非常有用,主要被用在 Swift 類的初始化過(guò)程中。
下面的栗子展示了在訪問(wèn)被明確為 String 的可選項(xiàng)展開值時(shí),可選字符串和隱式展開可選字符串的行為區(qū)別:
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark
你可以把隱式展開可選項(xiàng)當(dāng)做在每次訪問(wèn)它的時(shí)候被給予了自動(dòng)進(jìn)行展開的權(quán)限(編譯器自動(dòng)在操作前補(bǔ)上一個(gè)!進(jìn)行拆包,然后在執(zhí)行后面的操作,當(dāng)然如果該值是nil,也一樣會(huì)報(bào)錯(cuò)crash掉),這樣就可以在聲明可選項(xiàng)的時(shí)候添加一個(gè)嘆號(hào)而不是每次調(diào)用的時(shí)候在可選項(xiàng)后邊添加一個(gè)嘆號(hào)。
你可以像對(duì)待普通可選一樣對(duì)待隱式展開可選項(xiàng)來(lái)檢查里邊是否包含一個(gè)值:
if assumedString != nil {
print(assumedString)
}
// prints "An implicitly unwrapped optional string."
你也可以對(duì)待隱式展開可選項(xiàng)通過(guò)可選項(xiàng)綁定在一句話中檢查和展開值:
if let definiteString = assumedString {
print(definiteString)
}
// prints "An implicitly unwrapped optional string."
合并空值運(yùn)算符
上面對(duì)可選類型的三種處理不是需要繁瑣的判斷就是存在Crash風(fēng)險(xiǎn)不夠安全,那么??的出現(xiàn)很好的解決了這個(gè)問(wèn)題。
合并空值運(yùn)算符 (a ?? b )如果可選項(xiàng) a 有值則展開,如果沒(méi)有值,是 nil ,則返回默認(rèn)值 b 。表達(dá)式 a 必須是一個(gè)可選類型。表達(dá)式 b 必須與 a 的儲(chǔ)存類型相同。
合并空值運(yùn)算符是下邊代碼的縮寫:
a != nil ? a! : b
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"