- 原文地址: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、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。