Optional(可選類型)
Optional是Swift中引入的新類型. 表示可以有值也可以沒值. 當(dāng)它沒值時, 就是nil. Optional類型其實是枚舉:
enum Optional<T> : Reflectable, NilLiteralConvertible {
case None
case Some(T)
init()
init(_ some: T)
/// Haskell's fmap, which was mis-named
func map<U>(f: (T) -> U) -> U?
func getMirror() -> MirrorType
static func convertFromNilLiteral() -> T?
}
當(dāng)Optional沒有值時,返回的nil其實就是Optional.None,即沒有值。除了None以外,還有一個Some,當(dāng)有值時就是被Some<T>包裝的真正的值,所以我們拆包的動作其實就是將Some里面的值取出來。
Swift和OC中nil的區(qū)別
- OC中,
nil是一個指向不存在對象的指針; - Swift中,
nil不是指針,它是一個確定的值,用于表示值缺失。任何類型的可選狀態(tài)都可以設(shè)置為nil,不只是對象類型(當(dāng)基礎(chǔ)類型(整形、浮點、布爾等)沒有值時,也是nil);
定義
定義一個Optional的值只需要在類型后面加上問號(?),如:
var str: String?
另外:在上面可以看到,Optional其實就是一個枚舉,然后給它指定一個類型就行了,所以下面這兩種方法都能聲明一個Optional值:
var str: String! = "Hello World!"
var str2: Optional<String>
一個Optional值和非Optional值的區(qū)別就在于:Optional值未經(jīng)初始化雖然為nil,但普通變量連nil都沒有:
//未被初始化,但是是一個Optional類型,為nil
var str: String?
str //輸出nil
//未被初始化,也不是Optional類型
var str2: String
str2 //使用時出錯
使用
關(guān)于! 和 ? 使用場景
?的使用場景:
1)聲明Optional值變量
2)在對Optional值操作中,用來判斷是否能響應(yīng)后面的操作
!的使用場景:
1)強制對Optional值進(jìn)行拆包
2)聲明隱式拆包變量,一般用于類中的屬性
**對于可選類型, 使用之前需要拆包才不會報錯. 拆包有兩種方式. **
顯式拆包
- Optional Binding
正常情況下,
let pet = jackon.pet的返回值不是Bool,而是“有值”或者“沒有值”,不能直接用于條件表達(dá)式。但是if let的搭配是一種僅僅針對Optional類型的特殊的情況,蘋果有意在編譯器做了這種處理。
if let str = strValue {
let hashValue = str.hashValue
}
-
通過! str!
對比拆包前后,對str的輸出:var str: String? = "Hello World!"
str //{Some "Hello World!"}
str! //Hello World!
隱式拆包
通過在聲明時的數(shù)據(jù)類型后面加一個感嘆號(!)來實現(xiàn):
var str: String! = "Hello World!"
str //Hello World!
可以看到?jīng)]有使用(?)進(jìn)行顯式的折包也得到了Some中的值,這個語法相當(dāng)于告訴編譯器:在我們使用Optional值前,這個Optional值就會被初始化,并且總是會有值,所以當(dāng)我們使用時,編譯器就幫我做了一次拆包。如果你確信你的變量能保證被正確初始化,那就可以這么做,否則還是不要嘗試為好。
Optional Chaining
當(dāng)一個Optional值調(diào)用它的另一個Optional值的時候,Optional Chaining就形成了,基本上,Optional Chaining就是總是返回一個Optional的值,只要這個Chaining中有一個值為nil,整條Chaining就為nil,和Objective-C的向nil發(fā)消息類似。
//不使用Optional Chaining需要判斷兩次
if let pet = jackon.pet {
if let toy = pet.favoriteToy {
toy.name
}
}
//使用Optional Chaining只需要判斷一次
if let toy = jackon.pet?.favoriteToy {
toy.name
}
Optional Chaining除了能將屬性返回的類型變?yōu)?code>Optional外,連方法的返回值都能強制變?yōu)?code>Optional,哪怕這個方法沒有返回值,但是別忘了,Void也算是一個類型:
typealias Void = ()
如果Pet類有一個玩玩具的play方法的話,就可以這樣來判斷是否會調(diào)用成功:
if let p: Void = jackon.pet?.play() {
"play is called"
}