個人總結Swift 中可選值(Optional)

Optional的定義

Optional是 OC 中沒有的數據類型,是蘋果在 Swift 中引入的全新類型,它的特點就是可有值,也可以沒有值,當它沒有值的時候就是 nil. 并且 Swift 中的nil 和 OC 中 nil 也不一樣,在 OC 中只有對象才能為 nil, 而在 Swift 中,當基礎類型(整型,浮點,布爾等)沒有值的時候,也是 nil, 而不是一個初始值,沒有初始值的值是不能使用的,所以就產生了 Optional 類型.定義一個 Optional 的值很容易,只需要在類型后面加上問號(?)就行了,例如:

var str: String?
let status: Int? = 1   // 申明可選Int類型的常量,初始值為1 
var defaultAddress: String? = "江蘇南京"   // 申明可選String類型的變量,初始值為"江蘇南京"
var student: Person? // 申明可選Person(自定義的類)的變量,初始值為nil

注意:
  Int?和 Int 不相同, Int? 代表可選的 Int 類型,可以賦值為 nil, 而 Int 不可以賦值為 nil

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

//未被初始化,但是是一個Optional類型,為nil
var str: String?
str //輸出nil
//未被初始化,也不是Optional類型
var str2: String
str2    //使用時出錯

Optional 的拆包

顯式拆包

Optional 類型的值不能被直接使用,當需要用時要顯示拆包,以表明我知道這個 Optional 是一定有值的:

var str: String? = "Hello World!"
str! //Hello World!

對比拆包前后, str 的輸出

var str: String? = "Hello World!"
str     //{Some "Hello World!"}
str!    //Hello World!

之所以要拆包使用,是因為 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?
}

當 Optional 沒有值的時候,返回的 nil 其實就是 Optional.None, 沒有值.除了 None 之外,還有一個 some, 當有值的時候就是被 Some<T>包裝的真正的值,所以我們拆包的動作其實就是將 Some 里面的值取出來

注意:

1.在拆包的時候,如果是網絡請求的參數中有可選值的時候,一定都要拆包,不然的話只要有一個Optional 類型的參數沒有進行解包,所有的參數都會變成 Optional 類型的
  2.使用"!"強制解包獲取可選類型的值的時候容易造成程序崩潰(不建議直接使用)

var defaultAddress: String? = "上海"
if defaultAddress != nil { // !=或==可以用來判斷是否為nil
    print("您的地址是\(defaultAddress!)") // 使用!強制解析
} else {
    print("對不起,您不存在地址信息")
}
var student: Person?
print("學生為\(student!)") // XCode會提示運行錯誤,因為student初始值為nil,強制解析不行

隱式拆包

除了顯示拆包之外, Optional 還提供了隱式拆包,通過在聲明時的數據類型后面加一個感嘆號(!)來實現

var str: String! = "Hello World!"
str //Hello World!

可以看到沒有使用(?)進行顯式的折包也得到了Some中的值,這個語法相當于告訴編譯器:在我們使用Optional值前,這個Optional值就會被初始化,并且總是會有值,所以當我們使用時,編譯器就幫我做了一次拆包。如果你確信你的變量能保證被正確初始化,那就可以這么做,否則還是不要嘗試為好。
  另外:在上面可以看到,Optional其實就是一個枚舉,然后給它指定一個類型就行了,所以下面這兩種方法都能聲明一個Optional值:

var str: String! = "Hello World!"
var str2: Optional<String>

空運算符

可以用來判斷變量或常量是否為nil

// 空合運算符:a ?? b 判斷a是否為nil,若a不為nil對a解包,否則返回b的值
var status: Int? // 申明可選Int類型的變量status,初始值為nil
status ?? 0 // 因為status為nil,則返回0
// ?? 即為以下if else的縮寫
func testOption() -> Int {
    let status: Int? = 1
    if status == nil {
        return 0
    } else {
        return status!
    }
}

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 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,能使我們的代碼變得更加可讀,同時更加簡潔。
  在我總結 Swift 的時候發現一篇簡書寫的也不錯簡書

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容