1. 程式人生 > >如何理解Swift中Optional的 ! 和 ?

如何理解Swift中Optional的 ! 和 ?

需要 ring 產生 類型 展示 pen 編譯錯誤 默認 www.

很多人在剛上手swift時對於Optional中 ‘!’ 和 ‘?’ 的使用十分不理解,接下來我會談一談自己對於這兩個符號的使用方式的理解。

先來說說Optional的概念,以方便之後的理解。來看一下下面的代碼:

var a : String = nil // 編譯錯誤,String類型不能為nil
var b : String = “Hello!”
1
2
Swift 中的普通類型不再能設為nil。那如何表示這個值不存在呢?所以引進了Optional的概念:代表 nil 或某個具體的值。例如:

var c : String? = nil
var d : String? = “Hello!”
1
2
String? 就是一個Optional,它既能夠被具體類型賦值, 也可以賦值為nil。通過 String 和 Optional的比較,發現Optional 就相當於把具體類型和 nil 打包捆綁在了一起,轉變成了一種新的類型。

Optional 有兩種聲明方法:

var apple: String?
var bread: String!
1
2
很多人認為,聲明為 String! 的變量表明該變量的值不為 nil。但是,實際上,String! 和 String? 都是有默認值的,且默認值都為nil。我們為它們賦一個初值再打印類型來看看:

var apple: String? = “apple”
var bread: String! = “bread”
1
2
(lldb) p apple
(String?) $R0 = “apple”

(lldb) p bread
(String?) $R1 = “bread”

發現,盡管apple 和 bread 雖然一個是 String? 一個是 String! 但是打印出來都是 String? 類型的。所以更恰當的理解應該是:String! 只是理解意義上的不為nil,其本質還是一個 Optional,從聲明來說它和 String? 完全等價,所以也能夠賦值為 nil 。

為了之後敘述方便,我們把定義類似 String? 的稱為 Optional(www.chonylpt.com?), 定義類似 String! 的稱為 Optional(!)。

Optional 的本質是囊括 nil 和具體類型的一種枚舉。獲取它具體值的操作過程稱之為拆包,用 “!” 表示。先來做個實驗:

var string : String
var optionalString: String?
var nonOptionalString: String!

string = nonOptionalString // ① 崩潰
string = optionalString // ② 編譯錯啦
string = optionalString! // ③ 崩潰
具體看一下報錯原因:
① String! 賦值給 String ,報錯為:拆包時Optional的值為nil;
② String? 賦值給 String,編譯器報錯為 Optional未拆包;
③ 拆包後的 String? 賦值給 String,這時,報錯為:拆包時Optional的值為nil;
String! 和 拆包後的 String? 進行傳值時報的錯相同,由此我們可以得出一個結論:編譯器默認 Optional(!) 是確定有值的,所以不需要再對 nil 的情況進行處理。Optional(!) 的變量只是給予了自動拆包的權限,在實際使用它的過程中不需要再次使用 ‘!’ 進行拆包。在swift官方文檔中稱為:Implicitly Unwrapped Optional (隱式拆包),也可以理解成“拆過包了”。

但是,只有在變量確認有值的情況下才能進行拆包。就像如上代碼,optionalString 為nil,進行拆包就會引發崩潰。swift官方建議,Optional 使用 if + ! 結合的方式或者 if let 進行安全地拆包。簡單的看下代碼:

if optionalString != nil {
append(string: www.078881.cn/ optionalString!)
} else {
// do something

if let actualString = optionalString {
append(string: actualString)
} else {
// do something
再次提醒一下,Optional(!) 和 www.yongshiyule178.com Optional(?) 都可以使用這兩種方式進行安全地拆包,只是編譯器不會對沒有處理 nil 情況的 Optional(!) 報錯。

下圖展示了 Optional 和 String 可接收類型的比較:

拆完包之後的 Optional 其實就是 String 類型。編譯器強制使用者在變量為 nil 的時候要進行處理,否則就會報錯會崩潰。String! 是為了規避變量一定不為 nil 的情況下卻要反復判斷是否為 nil 的冗余代碼而產生的。例如,我們在使用 IBOutlet 時,一定會定義成 Optiona(!)。String! 在聲明時和 String? 完全等價,在使用時和 String 完全等價。

總結一下:

Optional的本質是一個包含了 nil 和普通類型的枚舉,這是為了確保使用者在變量為 nil 的情況下會完成相應的處理;
無論是 Optional(!) 還是 Optional(?) 都是一種Optional,在未設初始值時,默認為nil。Optional(!) 只是給予了自動拆包的權限,省略了判斷其值是否為nil的過程,但是不能夠保證它的值不為nil;
Optional(!) 在聲明時和 Optional(?) 等價,在使用時和具體類型等價;
一定要確保 Optional 不為 nil 的情況下才可直接拆包,不然會引發崩潰。

如何理解Swift中Optional的 ! 和 ?