- 原文地址:Swift 5 Frozen enums
- 原文做者:Keith Harrison
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:iWeslie
- 校對者:Lobster-King
你是否已經將你的 Xcode 工程升級到了兼容 Swift 5?升級 Swift 5 基本不會有大問題,但當你用 switch 語句去枚舉一個未知值的時候可能會遇到不少警告。。前端
究竟是什麼問題呢?我如今用一小段代碼展現爲不一樣大小的類適配佈局。它枚舉出了 UIUserInterfaceSizeClass
的 全部可能值:android
func configure(for sizeClass: UIUserInterfaceSizeClass) {
switch sizeClass {
case .uppercased:
// ...
case .compact:
// ...
case .regular:
// ...
}
}
複製代碼
當我把項目升級到 Swift 5 以後,Xcode 會報出一些警告:ios
警告內容:git
Switch 語句涵蓋了全部 case,可是
UIUserInterfaceSizeClass
之後能夠會添加一些其餘未知的值github請使用 「@unknown default」 來處理未知值objective-c
若是你點擊了修復,Xcode 會自動添加一個 @unknown default:
的 case:swift
switch sizeClass {
case .unspecified:
// ...
case .compact:
// ...
case .regular:
// ...
@unknown default:
fatalError()
}
複製代碼
你能夠修改 fatalError()
,但這究竟是什麼意思呢?後端
Swift 中的一個 switch
語句必須是詳盡的或者包含一個默認的 default case 來處理其餘全部狀況。我原來的 switch 語句把在 Apple 在 iOS 12 的 UIKit
中定義的 UIUserInterfaceSizeClass
的全部可能值都進行了枚舉。app
若是 Apple 在 iOS 13 中引入了 .tiny
或 .large
,那會發生什麼呢?使用新版本的 SDK 編譯時,編譯器會因 switch 語句再也不詳盡而報錯。解決錯誤的的一種方法是引入一個 default:
case。我能夠重寫個人 switch 語句:框架
switch sizeClass {
case .compact:
// 佈局爲 compact 該作的事
default:
// 默認狀況下該作的事
// 其中也包含了一些未知狀況
}
複製代碼
該 switch 再也不詳盡,但它能處理全部如今已知和將來的未知的狀況。這一點很好,但若是 switch 是詳盡的,這對編譯器就有優點,而且它在編譯時能兼容二進制庫。當枚舉更新後有新的 case,你可能還須要警告。
Swift 進化的提案 SE-0192 添加了 @unknown default:
語法,這容許你能夠繼續使用一個詳盡的 switch 來用於將來可能出現的狀況:
switch sizeClass {
case .unspecified:
// ...
case .compact:
// ...
case .regular:
// ...
@unknown default:
// ...
}
複製代碼
@unknown default:
這個 case 只能用於讓枚舉變得詳盡,並匹配添加到枚舉的任何新案例。它依舊會爲這些新 case 生成警告,以便你能夠決定採起怎麼樣的操做。這不一樣於使用 default:
和一個非詳盡的枚舉,它不會提示你有新的 case 未處理。
這一變化還增長了 凍結枚舉 的概念,這不是爲了得到任何新 case。它僅適用於在 Swift 裏導入 C 或 Objective-C 的枚舉。舉個例子,標準庫中的 ComparisonResult
。這是他在 Objective-C 中的定義:
typedef NS_CLOSED_ENUM(NSInteger, NSComparisonResult) {
NSOrderedAscending = -1L,
NSOrderedSame,
NSOrderedDescending
};
複製代碼
只有三種可能的狀況,因此這個枚舉永遠不會改變。注意 NS_CLOSED_ENUM
註釋而不是一般的 NS_ENUM
。咱們並不須要在 switch 裏添加 @unknown default
來讓它變得詳盡:
let result: ComparisonResult = ...
switch result {
case .orderedAscending:
// ...
case .orderedSame:
// ...
case .orderedDescending:
// ...
}
複製代碼
若是庫的做者將新 case 添加到了凍結枚舉,則編譯會報錯。
咱們不知道 Apple 是否計劃在 UIKit
和相關框架中枚舉的狀況。大多數多是非冷凍的,但在某些狀況下,冷凍多是有意義的。
例如,堆棧視圖軸是一個 UILayoutConstraintAxis
的枚舉,在 iOS 12 中仍未凍結。這是 Objective-C 的頭文件(注意 NS_ENUM
):
typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {
UILayoutConstraintAxisHorizontal = 0,
UILayoutConstraintAxisVertical = 1
};
複製代碼
這意味着若是要打開堆棧視圖軸,則須要容許未來可能的未知狀況:
switch stackView.axis {
case .horizontal:
// ...
case .vertical:
// ...
@unknown default:
// ...
}
複製代碼
也許 Apple 會將其更改成 NS_CLOSED_ENUM
,又或者堆棧視圖是否會在 iOS 13 有別的可能值?
@unknown default:
。Xcode 會發出警告來提示你須要添加的位置。default:
case,那就不須要進行任何變化。default:
)是 Swift 5 中的警告。@unknown:
的 case 並消除警告。有關更多詳細信息,請參閱 Swift 進化的提案:
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。