把 swift 升級到 5.0 的時候相信大家一定會遇到建議新增 @unknown default
的警告:
@unknown default
解決的兩個問題
未來增加新的 case 後不會影響原有程式碼的編譯
如果 switch 語句中覆蓋了列舉的每個 case,那麼未來這個列舉如果增加了一個值,一定會對原來呼叫的程式碼造成 break change。如果是我們自己定義的列舉還好改,如果是系統級的庫就會造成很大的影響。大概也是考慮到 swift 5.0 開始 ABI 穩定的承諾,引入 @unknown default
對未來列舉的擴充套件新值時保證相容性提供了很好的支援。
在有新的列舉值時編譯器可以提醒
如果在 switch 語句中使用了 default
,如果未來新增了列舉值也不會破壞到呼叫程式碼的編譯。但是使用者會很難發現有新的列舉選項產生了。Apple 舉了一個 UIKeyboardType
的例子,這已經是一個非常早期就存在的列舉,但是在 iOS 10 中還是新增了 asciiCapableNumberPad
了這個選項。iOS 每個版本升級底層都會增加了一些功能,使用@unknown default
標記在 switch 語句中,如果有新的列舉值編譯器就可以很好的提示使用者有新的 case 需要處理。
Frozen enum
有些列舉未來可能會變動,有些在宣告的時候就很確定不會改變。這種狀態 apple 稱之為 frozen。列舉有兩種可能:frozen(不變的)和 non-frozen(值會變的)。原來 OC 中的所有列舉預設都認為是 non-frozen 的。
如果想要把列舉宣告為 non-frozen,使用 NS_CLOSED_ENUM
宣告:
typedef NS_CLOSED_ENUM(NSInteger, NSComparisonResult) {
NSOrderedAscending = -1L,
NSOrderedSame,
NSOrderedDescending
};
複製程式碼
影響範圍
目前 @unknown default
只針對 C 風格的 enum 和 Foundation 中的列舉起作用,使用者在 swift 自定義的列舉都認為是 frozen 的。
我也不是很理解為什麼這個列舉的型別區分只支援 OC,swift 不支援。這個特性如果被社群接受的話,猜測 swift 在未來版本也會支援使用者自定義的 swift 列舉也可以標記為 non-frozen。
延伸閱讀:
- 微博:@沒故事的卓同學
- 掘金部落格
- 如果想與我有更密切的交流也可以加入我的知識星球:iOS 程式設計師保護協會