目前工作上已經穩定的在用 Swift 開發了,對於 Optional 變數也越用越熟悉了。前陣子在台北的一個 iOS 相關的聚會上知道有 Optional Chaining 這個東西之後,就開始在實務專案中大量的使用。
(這篇不會詳細講 optional 和 optional chaining 是什麼東西)
來點前言
源自對 if-let 和 guard-let-else 的繁雜感
這兩個東西在撰寫的時候,一定要製造出三行以上的空間給他,內心深處的某處是覺得這樣不是那麼漂亮;其中的 statement 可能又只有一行 return
。
使用 optional chaining 對我來說可能就是比較好的解法吧!我想撰寫上也會比較漂亮吧。
源自驚嘆號的危險性
把一個變數用驚嘆號 unwrap 的危險就是,當裡面的值是 nil 的話,就一定會 crash 。如果是透過 ?
使用的話,就會比較安全。
給個例子好了,這樣子在 runtime 就會出事:
let property: AnyObject? = nil
print(property!) // 這樣就會 crash
這樣子寫則是會天下太平般的度過:
let property: AnyObject? = nil
print(property?) // 這樣就不會 crash 了
來個串成 optional chaining 的例子:
let status = self.selectedViewController?.currentStatus ?? .Default
如果要寫成 guard-let-else 的樣子的話,就要
1. 先判斷 self.selectedViewController
是不是空值
2. 接著再去判斷 currentStatus (這裡先假設這是個 enum)是不是 nil
3. 如果是 nil 的話,再手動給一個 .Normal 的狀態給他
這個例子使用了 optional chaning ,再透過 ??
給它預設值,雖然有多了一些 ?
在程式碼裡面,但是我覺得這樣寫在一些情境下會比使用 guard-let-else 這類的方式還要好維護。
使用的心得
用了一陣子 optional 和 optional chaining 之後,發現有些優缺點,想要分享一下。
優點
- 可以避免不經意的 crash ,當變數是 nil 時,也可以安全地渡過
- 不會有要判斷是否有值而必須寫大括弧
{}
的區塊 - 比較易讀 (個人感想)
(可能還有一些優點還沒想到或感受到)
缺點
- 當一個變數的值是 nil 的時候不會出事,但是只要沒有檢查、就不太容易察覺有問題
- 問號遍佈 (這個的接受度好像就因人而異了)
- optional chaining 在某些情形會有需要給預設值,在某些情境下給預設值會覺得不對勁,甚至會想到會不會對於記憶體用量會有什麼影響。
其中一個缺點有點像是 Objective-C 裡面處理 nil
的感覺:當 optional chaining 遇到第一個 nil 之後,該行接續下來的指令就都不會執行了,在 runtime 也不會報錯;若在撰寫的時候沒有注意到這個部分的話,也是可能會造成邏輯錯誤。換句話說就是使用的時候需要知道自己在做什麼事。
(以上可能還有一些缺點還沒想到或感受到)
結語和我自己的想法
宣告
當在 class 裡面宣告 property 的型別的時候,我認為沒有宣告成 optional type 的話,在大部分的情形下是很危險的。
因此我基本上都會這樣宣告:
var name: String?
var viewContainer: UIView?
在取用的時候一致加上 ?
或是用 ??
給予預設值;當不想要給預設值的情境下,可能就會需要先用 guard-let-else 過濾掉。
盡可能地避免使用 !
在呼叫的時候盡可能地避免使用 !
,要是在 runtime 的時候發生未預期會有空值的情形之下,基本上是無法挽回;所以除非必要,不要用驚嘆號。
再之後
寫這篇文章是在 Swift 2.2 版本,之後 Swift 會怎麼變化、 coding style 會怎麼樣適應變化還是未知數。
現在則是有點對 Swift 3.0 (就是現在外面風聲鶴唳的說要大改的那個版本)有點期待,不過目前看 Swift 官方目前對於 3.0 的規劃,看起來衝擊好像也不會太大(我是這麼覺得啦)。等到時候再來寫心得吧!