Swift 可選值(Optional Values)介紹

Optional的定義

Optional也是Objective-C沒有的數據類型,是蘋果引入到Swift語 言中的全新類型,它的特色就和它的名字同樣:能夠有值,也能夠沒有值,當它沒有值時,就是nil。此外,Swift的nil也和Objective-C有 些不同,在Objective-C中,只有對象才能爲nil,而在Swift裏,當基礎類型(整形、浮點、布爾等)沒有值時,也是nil,而不是一個初 始值,沒有初始值的值,是不能使用的,這就產生了Optional類型。定義一個Optional的值很容易,只須要在類型後面加上問號(?)就好了, 如:spa

var str: String?

一個Optional值和非Optional值的區別就在於:Optional值未經初始化雖然爲nil,但普通變量連nil都沒有:.net

//未被初始化,可是是一個Optional類型,爲nil

var str: String?

str //輸出nil

//未被初始化,也不是Optional類型

var str2: String

str2    //使用時出錯

Optional的拆包

顯式拆包

Optional類型的值不能被直接使用,當須要用時要顯式拆包,以代表我知道這個Optional是必定有值的:code

var str: String? = "Hello World!"

str! //Hello World!

對比拆包先後,對str的輸出:對象

var str: String? = "Hello World!"

str     //{Some "Hello World!"}

str!    //Hello World!

之因此要拆包使用,是由於Optional類型實際上是一個枚舉: ci

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?

}

當Optional沒有值時,返回的nil其實就是Optional.None,即沒有值。除了None之外,還有一個Some,當有值時就是被Some<T>包裝的真正的值,因此咱們拆包的動做其實就是將Some裏面的值取出來。get

有沒有似曾相識的感受?Java裏面也有泛型。

隱式拆包

除了顯式拆包,Optional還提供了隱式拆包,經過在聲明時的數據類型後面加一個感嘆號(!)來實現:編譯器

var str: String! = "Hello World!"

str //Hello World!

可 以看到沒有使用(?)進行顯式的折包也獲得了Some中的值,這個語法至關於告訴編譯器:在咱們使用Optional值前,這個Optional值就會被 初始化,而且老是會有值,因此當咱們使用時,編譯器就幫我作了一次拆包。若是你確信你的變量能保證被正確初始化,那就能夠這麼作,不然仍是不要嘗試爲好。it

 

另外:在上面能夠看到,Optional其實就是一個枚舉,而後給它指定一個類型就好了,因此下面這兩種方法都能聲明一個Optional值:io

var str: String! = "Hello World!"

var str2: Optional<String>

Optional Binding

在說Optional Binding以前,我想先說下Xcode6 Beta5在這一版中的一個小變化:在Xcode6 Beta5以前,若是是一個Optional值,能夠直接放到條件判斷語句中,如:編譯

var str: String? = "Hello World!"

if str {

    "not nil"

} else {

    "nil"

}

若是不是nil,則右邊的Playground會顯示「not nil」;反之則顯示「nil」,可是至Xcode6 Beta5開始,這樣就不能經過編譯器了,你須要用下面這種方式來代替:

var str: String? = "Hello World!"

if str != nil {

    "not nil"

} else {

    "nil"

}

看似合理,可是在某種狀況下會很是不爽難過,好比你在str != nil條件成真後接着在上下文中使用str,會被要求進行拆包,咱們以一個Int類型的Optional來作示例:

var count: Int?

count = 100

if count != nil {

    "count is " + String(count!)    //count is 100

} else {

    "nil"

}

我在把count強轉成String的時候被要求拆包了,這是由於count自己是一個Optional的類型,爲了不在條件判斷語句後執行一次或更屢次的拆包,Swift引進了Optional Binding,咱們就能夠這樣作:

var count: Int?

count = 100

if let validCount = count {

    "count is " + String(validCount)    //count is 100

} else {

    "nil"

}

經過在條件判斷語句中(如if、while等)把Optional值直接給一個臨時常量,Swift會自動檢測Optional是否包含值,若是包含值,會隱式的拆包並給那個臨時常量,在接下來的上下文中就能直接使用這個臨時常量了,這樣是否是就以爲很爽呢微笑

 

注:在Optional Binding中,除了以常量的方式去接收拆包的值以外,也能以一個變量的形式去接收,但相信在大多數狀況下咱們只是使用那個值就好了,並不會去改變它。

 

Swift 1.2 新語法:

在if let 中可使用條件判斷了: 

var a: NSString?

a = "test"

if let b = a {

    b

}


if true, let b = a where b == "test" {

    "true"

}

若是a 不是"test",則不會打印出"true"

 

Optional Chaining

Optional Chaining對Swift來講是很基本但又必不可少的東西,相對於簡單類型(Int、String等)來講,Optional更主要的應用場景是在復 雜對象上,當一個對象包含另外一個對象,同時這兩個對象都有可能爲nil的狀況下才是Optional派上用場的地方,在Objective-C裏,向 nil發消息獲得的就是一個nil,可是Swift不能在nil上直接調用方法或屬性,同時爲了方便咱們使用,從而引入了Optional類型,但是這還 不夠,咱們作一個簡單的例子:

class Person {

    var pet: Pet?

}


class Pet {

    var name: String

    

    var favoriteToy: Toy?

    

    init (name: String) {

        self.name = name

    }

}


class Toy {

    var name: String

    

    init (name: String) {

        self.name = name

    }

}

一 個Person對象表明一我的,這我的可能有一個寵物,寵物會有它本身的名字,並且寵物可能會有本身喜好的玩具,按照前面提到的知識,咱們要首先判斷這個 人有沒有寵物,而後再判斷他的寵物有沒有喜好的玩具,而後才能獲得這個玩具的名稱,利用Optional Binding,咱們寫出來的可能就像這樣:

let jackon = Person()

jackon.pet = Pet(name: "Max")

jackon.pet?.favoriteToy = Toy(name: "Ball")

if let pet = jackon.pet {

    if let toy = pet.favoriteToy {

        toy.name

    }

}

這裏用到了兩個if,由於pet和toy對象均可能爲nil,咱們須要預防每個可能爲nil的對象,若是這個對象再複雜一點,那if也就更多了,而使用Optional Chaining的話,寫出來的就像這樣:

let jackon = Person()

jackon.pet = Pet(name: "Max")

jackon.pet?.favoriteToy = Toy(name: "Ball")

if let toy = jackon.pet?.favoriteToy {

    toy.name

}

當一個Optional值調用它的另外一個Optional值的時候,Optional Chaining就造成了,基本上,Optional Chaining就是老是返回一個Optional的值,只要這個Chaining中有一個值爲nil,整條Chaining就爲nil,和Objective-C的向nil發消息相似。

有一點頗有趣,就是Optional Chaining除了能將屬性返回的類型變爲Optional外,連方法的返回值都能強制變爲Optional,哪怕這個方法沒有返回值,可是別忘了,Void也算是一個類型:

typealias Void = ()

若是咱們的Pet類有一個玩玩具的play方法的話,就能夠這樣來判斷是否會調用成功:

if let p: Void = jackon.pet?.play() {

    "play is called"

}

使用Optional Chaining,能使咱們的代碼變得更加可讀,同時更加簡潔。

相關文章
相關標籤/搜索