之前學習 swift 的時候都是比較破碎,零零散散,以至於有些地方學習的不夠透徹。所以趁最近有時間,就開始重新學習 swift ,從最基本的開始學習,希望能深入理解,見微知著!
關於 swift 我們都是到是型別安全型的,相較於 OC ,安全似乎更能體現出來。關於這一方面, swift的可選型(optional)就不得不說了,可選型可以說是 swift 最為突出的特性之一。可能有的同學在看 swift 的過程中會遇到可選型(比如 String?
),有時也會見到 String!
這樣的,搞不明白其中的意思,所以今天就來一步步理解可選型。
一、什麼是 Optional
optional 是 swift 新加入的型別,所以學過 OC 的童鞋就知道在 OC 中是沒有這個概念的。可選型的意思簡單理解是:有值得時候就有值,無值的時候就是 nil 。swift 中的 nil 和其他語言中的 nil 還有些不一樣,nil 自己本身就是一種型別,沒有就是 nil ,是和其他型別嚴格區分開的。
可選型的定義很簡單:型別 + ? 。比如 String?
、Int?
、Float?
等,這裡需要注意的是 String?
和 String
是完全不同的兩個型別,前者是 String
型別的額可選型,後者是 String
型別,注意區分。舉個例子,在 OC 中我們可以這樣寫
1 2 |
NSString *name = @"loveway"; name = nil; |
上面的這種寫法在 OC 中是沒有問題的,相比於上面,在 swift 中
1 2 |
var name: String = "loveway" name = nil |
如果我們像上面程式碼中這樣寫就會報錯,如下
說的是 nil 是不可以分配給 String 型別的,這也說明在 swift 中 nil 是和其他型別嚴格區分的。改為可選型即可,
1 2 |
var name: String? = "loveway" name = nil |
可選型,顧名思義就是可以選擇,比如 String?
的意思就是可以在 String
和 nil
之間選擇,可以是 String
也可以是 nil
。如果一個變數定義成 String
,那麼這個變數就會是 String
型別,而不可能是nil
。
還有一點需要注意的是宣告可選型必須是顯示的宣告也就是必須是
1 |
var name: String? = nil |
這樣,而不能是
1 |
var name = nil |
這樣,因為 swift 在做型別判斷的時候無法判斷 name 到底是 String 型別的可選型還是其他型別的可選型,因此會導致編譯錯誤。
二、Optional的解包
可選型是不能夠被直接使用的(因為 swift 是型別安全的,可選型的值又可能會是 nil,如果不做處理可能導致程式 crash),如果我們想使用可選型的值,那麼在這之前我們需要做的一項工作就是:解包(unwarp)!
- 1、強制解包
所謂的強制解包意思就是我知道這個型別是可選型,但是在我的程式執行到這裡的時候我可以保證它是有值得,所以我要在這裡使用它。具體表現形式就是在可選型後面加個!
,如下
12var name: String? = "loveway""My name is " + name!
但是這樣的解包是不安全,因為你不知道什麼時候你的這個可選型就會變成 nil,如果我們程式碼非常多的話,一不小心為 nil了,可能會導致程式崩潰。這個時候我們會想到一種方法:判空!如下,
123456var name: String? = "loveway"if name != nil {"My name is " + name!} else {print("name is nil")}
這樣寫似乎是沒有什麼問題了,但是需要注意的是,你在判斷非 nil 的作用域內使用 name 的時候還必須把!
帶上,這樣程式碼比較多的時候還是比較麻煩。於是我們可以使用下面這種方式, - 2、使用
if let
解包
使用if let
解包如下,
123456var name: String? = "loveway"if let name = name {"My name is " + name} else {print("name is nil")}
這種解包方式可以保證 name 是解包過的,不會再是 nil 這種情況,其實邏輯是和上面做非空判斷一樣的。當然你把let
換成var
也是可以的,效果是一樣的,只不過我們一般要用的是解包後的值,而不會去改變它,所以平常使用中一般都是用if let
。
同時if let
可以同時一次性解包多個可選型,用,
隔開,使語句簡潔,如下
1234567var name: String? = "loveway"var age: Int? = 18if let name = name, age = age {"My name is " + name} else {print("name is nil")}
最後,既然這裡使用的是if
,那麼同樣我們可以如下這樣用,來進行進一步的判斷篩選
1234567var name: String? = "loveway"var age: Int? = 18if let name = name, age = age where age == 18 {print("My name is \(name), age is \(String(age))")} else {print("name is nil")}
如上也是可以的。
三、可選鏈式呼叫(Optional Chaining)
可選鏈式呼叫(Optional Chaining)是一種可以在當前值可能為 nil 的可選值上請求和呼叫屬性、方法及下標的方法。如果可選值有值,那麼呼叫就會成功,如果可選值是 nil ,那麼呼叫將返回 nil。多個呼叫可以連線在一起形成一個呼叫鏈,如果其中任何一個節點為 nil ,整個呼叫鏈都會失敗,即返回 nil 。
下面我們就來舉個例子具體說明可選鏈,如下
1 2 3 4 5 6 |
var name: String? = "loveway" if let name = name { print(name.uppercaseString) } else { print("name is nil") } |
我們來解包 name ,如果有值就列印出 name 的大寫,如果沒有就輸出 name is nil
,其實上面這段程式碼完全等同於
1 2 |
var name: String? = "loveway" name?.uppercaseString |
上面這句程式碼的意思就是如果可選型變數 name 有值,那麼就對 name 進行解包,並得到 name 的uppercaseString 值,如果沒有,那麼這句程式碼就會返回一個 nil 。這樣就符合 swift 的型別安全,完全是沒有問題的。但是如果你寫成
1 2 |
var name: String? = "loveway" name!.uppercaseString |
也是可以的,不過不安全,因為如果 name 沒有值,你進行強制解包,就會報錯。
所以我們以後可能會用到類似於 person?.name?.uppercaseString
這樣的一層層解包的,這種就是可選鏈。
四、Nil Coalescing Operator(空合運算子)
如上,如果我們想把解包後的值存起來的話,可以這樣
1 |
let newName = name == nil ? "no name" : name! |
上面程式碼的意思就是如果 name 為 nil ,newName 就是 “no name”,否則 newName 就是 name!(name的解包)。其實 swift 為我們提供了更簡潔的語法,如下
1 |
let newName2 = name ?? "no name" |
上面程式碼的意思就是 name 如果有值 newName2 的值就是 name! ,否則就是 no name 。這裡需要注意的是 ??
是空合運算子,這樣寫的可閱讀性強,比較簡潔。
當然關於 ??
遠不止這些,有興趣的同學可以看 聊聊swift語言中的“??” 這篇文章。
五、隱式可選型
上面我們都知道了,建立一個顯示可選型是: 型別 + ?
。這裡建立顯示可選型的就是: 型別 + !
。
1 |
var name: String! = "loveway" |
這裡可能有的童鞋會疑惑,已經有了顯示的可選型,為什麼還需要有隱式的可選型。這裡其實隱式的可選型也是有一定作用的。比如你有一個變數,宣告為隱式的可選型(!
),它的作用就是,當你這個類沒有被初始化的時候他是沒有值的,但是當你這個類初始化以後,你可以確保他是有值的,所以這裡宣告為隱式的可選型,而不是顯示的。同樣需要注意的是隱式的可選型也是可選型,如果你需要用它的值,你也是要進行判斷的。如果不進行判斷而直接使用,可能會造成不可預料的後果!
差不多可選型就到這裡了,如果還有什麼遺漏,歡迎大家指正!