之前學習 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 中我們可以這樣寫
NSString *name = @"loveway";
name = nil;
複制代碼
上面的這種寫法在 OC 中是沒有問題的,相比于上面,在 swift 中
var name: String = "loveway"
name = nil
複制代碼
如果我們像上面代碼中這樣寫就會報錯,如下
說的是 nil 是不可以配置設定給 String 類型的,這也說明在 swift 中 nil 是和其他類型嚴格區分的。改為可選型即可,
var name: String? = "loveway"
name = nil
複制代碼
可選型,顧名思義就是可以選擇,比如
String?
的意思就是可以在
String
和
nil
之間選擇,可以是
String
也可以是
nil
。如果一個變量定義成
String
,那麼這個變量就會是
String
類型,而不可能是
nil
。 還有一點需要注意的是聲明可選型必須是顯示的聲明也就是必須是
var name: String? = nil
複制代碼
這樣,而不能是
var name = nil
複制代碼
這樣,因為 Swift 在做類型判斷的時候無法判斷 name 到底是 String 類型的可選型還是其他類型的可選型,是以會導緻編譯錯誤。
Tips: 當然枚舉類型的寫法還可以如
var name: Optional<String> = Optional.Some("Loveway")
複制代碼
這樣,隻不過我們一般都用
var name: String? = nil
複制代碼
這樣的簡寫。
二、Optional的解包
可選型是不能夠被直接使用的(因為 Swift 是類型安全的,可選型的值又可能會是 nil,如果不做處理可能導緻程式 crash),如果我們想使用可選型的值,那麼在這之前我們需要做的一項工作就是:解包(unwarp)!
- 1、強制解包 所謂的強制解包意思就是我知道這個類型是可選型,但是在我的程式執行到這裡的時候我可以保證它是有值得,是以我要在這裡使用它。具體表現形式就是在可選型後面加個
,如下!
var name: String? = "loveway"
"My name is " + name!
複制代碼
但是這樣的解包是不安全,因為你不知道什麼時候你的這個可選型就會變成 nil,如果我們代碼非常多的話,一不小心為 nil了,可能會導緻程式崩潰。這個時候我們會想到一種方法:判空!如下,
var name: String? = "loveway"
if name != nil {
"My name is " + name!
} else {
print("name is nil")
}
複制代碼
這樣寫似乎是沒有什麼問題了,但是需要注意的是,你在判斷非 nil 的作用域内使用 name 的時候還必須把
!
帶上,這樣代碼比較多的時候還是比較麻煩。于是我們可以使用下面這種方式,
- 2、使用
解包 使用if let
解包如下,if let
var name: String? = "loveway"
if let name = name {
"My name is " + name
} else {
print("name is nil")
}
複制代碼
這種解包方式可以保證 name 是解包過的,不會再是 nil 這種情況,其實邏輯是和上面做非空判斷一樣的。當然你把
let
換成
var
也是可以的,效果是一樣的,隻不過我們一般要用的是解包後的值,而不會去改變它,是以平常使用中一般都是用
if let
。 同時
if let
可以同時一次性解包多個可選型,用
,
隔開,使語句簡潔,如下
var name: String? = "loveway"
var age: Int? =
if let name = name, age = age {
"My name is " + name
} else {
print("name is nil")
}
複制代碼
最後,既然這裡使用的是
if
,那麼同樣我們可以如下這樣用,來進行進一步的判斷篩選
var name: String? = "loveway"
var age: Int? =
if let name = name, age = age where age == {
print("My name is \(name), age is \(String(age))")
} else {
print("name is nil")
}
複制代碼
如上也是可以的。
三、可選鍊式調用(Optional Chaining)
可選鍊式調用(Optional Chaining)是一種可以在目前值可能為 nil 的可選值上請求和調用屬性、方法及下标的方法。如果可選值有值,那麼調用就會成功,如果可選值是 nil ,那麼調用将傳回 nil。多個調用可以連接配接在一起形成一個調用鍊,如果其中任何一個節點為 nil ,整個調用鍊都會失敗,即傳回 nil 。 下面我們就來舉個例子具體說明可選鍊,如下
var name: String? = "loveway"
if let name = name {
print(name.uppercaseString)
} else {
print("name is nil")
}
複制代碼
我們來解包 name ,如果有值就列印出 name 的大寫,如果沒有就輸出
name is nil
,其實上面這段代碼完全等同于
var name: String? = "loveway"
name?.uppercaseString
複制代碼
上面這句代碼的意思就是如果可選型變量 name 有值,那麼就對 name 進行解包,并得到 name 的uppercaseString 值,如果沒有,那麼這句代碼就會傳回一個 nil 。這樣就符合 Swift 的類型安全,完全是沒有問題的。但是如果你寫成
var name: String? = "loveway"
name!.uppercaseString
複制代碼
也是可以的,不過不安全,因為如果 name 沒有值,你進行強制解包,就會報錯。 是以我們以後可能會用到類似于
person?.name?.uppercaseString
這樣的一層層解包的,這種就是可選鍊。
四、Nil Coalescing Operator(空合運算符)
如上,如果我們想把解包後的值存起來的話,可以這樣
let newName = name == nil ? "no name" : name!
複制代碼
上面代碼的意思就是如果 name 為 nil ,newName 就是 "no name",否則 newName 就是 name!(name的解包)。其實 Swift 為我們提供了更簡潔的文法,如下
let newName2 = name ?? "no name"
複制代碼
上面代碼的意思就是 name 如果有值 newName2 的值就是 name! ,否則就是 no name 。這裡需要注意的是
??
是空合運算符,這樣寫的可閱讀性強,比較簡潔。 當然關于
??
遠不止這些,有興趣的同學可以看 聊聊swift語言中的“??” 這篇文章。
五、隐式可選型
上面我們都知道了,建立一個顯示可選型是: 類型 +
?
。這裡建立隐式可選型的就是: 類型 +
!
。
var name: String! = "loveway"
複制代碼
這裡可能有的童鞋會疑惑,已經有了顯示的可選型,為什麼還需要有隐式的可選型。這裡其實隐式的可選型也是有一定作用的。比如你有一個變量,聲明為隐式的可選型(
!
),它的作用就是,當你這個類沒有被初始化的時候他是沒有值的,但是當你這個類初始化以後,你可以確定他是有值的,是以這裡聲明為隐式的可選型,而不是顯示的。同樣需要注意的是隐式的可選型也是可選型,如果你需要用它的值,你也是要進行判斷的。如果不進行判斷而直接使用,可能會造成不可預料的後果! 差不多可選型就到這裡了,如果還有什麼遺漏,歡迎大家指正!
- 參考連結:可選鍊式調用(Optional Chaining)