Overview
在 C 和 Objective-C 中稽莉,沒有可選項(xiàng)的概念炬称。在 Objective-C 中有一個近似的特性柜砾,一個方法可以返回一個對象或者返回 nil 稳其。 nil 的意思是“缺少一個可用對象”。然而耕驰,他只能用在對象上爷辱,卻不能作用在結(jié)構(gòu)體,基礎(chǔ)的 C 類型和枚舉值上耍属。對于這些類型托嚣,Objective-C 會返回一個特殊的值(例如 NSNotFound )來表示值的缺失巩检。這種方法是建立在假設(shè)調(diào)用者知道這個特殊的值并記得去檢查他厚骗。然而,Swift 中的可選項(xiàng)就可以讓你知道任何類型的值的缺失兢哭,他并不需要一個特殊的值领舰,它強(qiáng)調(diào)的是有沒有,而非空不空迟螺。
可以利用可選項(xiàng)來處理值可能缺失的情況冲秽。可選項(xiàng)意味著:
- 這里有一個值矩父,他等于x
或者 - 這里根本沒有值
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!
|
??var name: String!
|
普通類型
常量/變量聲明的時候類型后面不帶有?
或者!
為普通類型锉桑,也就是上表中1??,2??窍株,6??民轴,7??聲明方式
- 要么在聲明的時候賦初始值攻柠,要么在其所屬類的初始化方法中賦初始值,才能參與運(yùn)算
- 這種類型沒有默認(rèn)初始值后裸,且生命周期中不能接收nil
可選項(xiàng)(Optional Type)
常量/變量聲明的時候類型后面帶有?
或者!
為可選類型(optional type瑰钮,即可選項(xiàng)),也就是上表中3??微驶,4??浪谴,5??,8??因苹,9??苟耻,??聲明方式。
此外let name: Optinal<String>
的簡寫形式是4??容燕,二者作用跟和用法是完全一樣的梁呈; 同理let name: ImplicitlyUnwrappedOptional<String>
的簡寫形式是5??,二者作用跟和用法也是完全一樣蘸秘。
- 聲明為Optional常量時如果沒有賦初始值官卡,此常量沒有默認(rèn)值,需要在構(gòu)造函數(shù)中給常量設(shè)置初始數(shù)值
- 聲明為Optional的變量醋虏,如果不顯式的賦值就會有個默認(rèn)值
nil
- 聲明為Optional的變量/常量不能直接參與運(yùn)算寻咒,必須解包后才能參與運(yùn)算
- 解包后的Optional變量/常量如果沒有值(為
nil
)參與運(yùn)算也會發(fā)生Crash
我們可以對一個可選項(xiàng)類型(Optional Type)使用后綴操作符!
來強(qiáng)制拆包(force unwrap)訪問這個值,來繼續(xù)后面的操作颈嚼。
可選類型類似于Objective-C中指針的nil值毛秘,但是nil只對類(class)有用,而swift中可選類型對所有的類型都可用阻课,并且更安全叫挟。
強(qiáng)制展開
如果一個可選有值,它“不等于” nil 限煞,可以通過比較 nil 來判斷一個可選中是否包含值抹恳。
一旦你確定可選中包含值,可以使用后綴操作符!
來強(qiáng)制拆包(force unwrap)訪問這個值署驻,奋献,感嘆號的意思就是說“我知道這個可選項(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")
}
注意:
使用!
來獲取一個不存在的可選值會導(dǎo)致carsh宣吱,在使用!強(qiáng)制展開之前必須確鼻哉猓可選項(xiàng)中包含一個非 nil 的值。
可選項(xiàng)綁定
可以使用可選項(xiàng)綁定來判斷可選項(xiàng)是否包含值征候,如果包含就把值賦給一個臨時的常量/變量杭攻∪魇裕可選綁定可以與 if 和 while 的語句使用來檢查可選項(xiàng)內(nèi)部的值,并賦值給一個變量或常量朴上。
var myString:String?
myString = "Hello, Swift!"
if let yourString = myString {
print("你的字符串值為 - \(yourString)")
}else{
print("你的字符串沒有值")
}
//prints:你的字符串值為 - Hello, Swift!
隱式展開
有時在一些程序結(jié)構(gòu)中可選項(xiàng)一旦被設(shè)定值之后垒棋,就會一直擁有值。在這種情況下痪宰,就可以去掉檢查的需求叼架,不必每次訪問的時候都進(jìn)行展開,因?yàn)樗梢园踩拇_認(rèn)每次訪問的時候都有一個值衣撬。這種類型的可選項(xiàng)被定義為隱式展開可選項(xiàng)乖订。
通過在類型后邊添加一個嘆號( String! )而非問號( String? ) 來聲明一個隱式展開可選項(xiàng)。
在可選項(xiàng)被定義的時候就能立即確認(rèn)其中有值的情況下具练,隱式展開可選項(xiàng)非常有用乍构,主要被用在 Swift 類的初始化過程中。
下面的栗子展示了在訪問被明確為 String 的可選項(xiàng)展開值時扛点,可選字符串和隱式展開可選字符串的行為區(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)做在每次訪問它的時候被給予了自動進(jìn)行展開的權(quán)限(編譯器自動在操作前補(bǔ)上一個!進(jìn)行拆包哥遮,然后在執(zhí)行后面的操作,當(dāng)然如果該值是nil陵究,也一樣會報(bào)錯crash掉)
眠饮,這樣就可以在聲明可選項(xiàng)的時候添加一個嘆號而不是每次調(diào)用的時候在可選項(xiàng)后邊添加一個嘆號。
你可以像對待普通可選一樣對待隱式展開可選項(xiàng)來檢查里邊是否包含一個值:
if assumedString != nil {
print(assumedString)
}
// prints "An implicitly unwrapped optional string."
你也可以對待隱式展開可選項(xiàng)通過可選項(xiàng)綁定在一句話中檢查和展開值:
if let definiteString = assumedString {
print(definiteString)
}
// prints "An implicitly unwrapped optional string."
合并空值運(yùn)算符
上面對可選類型的三種處理不是需要繁瑣的判斷就是存在Crash風(fēng)險不夠安全铜邮,那么??
的出現(xiàn)很好的解決了這個問題仪召。
合并空值運(yùn)算符 (a ?? b
)如果可選項(xiàng) a 有值則展開,如果沒有值松蒜,是 nil 扔茅,則返回默認(rèn)值 b 。表達(dá)式 a 必須是一個可選類型秸苗。表達(dá)式 b 必須與 a 的儲存類型相同召娜。
合并空值運(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"