天天看點

重讀 Swift 之一:Optional(可選型)

之前學習 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)