该特性对应的proposal是–Swift evolution-Handling Future Enum Cases
@unknown default
在Swift 4中,这样写Switch case是没有任何问题的
// UIUserInterfaceSizeClass总共就下面三个case
let axis: UIUserInterfaceSizeClass = .unspecified
switch axis {
case .unspecified:
fallthrough
case .regular:
fallthrough
case .compact:
print("")
}
当升级到Swift 5后,编译器会给出一个正告
Switch covers known cases, but ‘UIUserInterfaceSizeClass’ may have additional unknown values, possibly added in future versions.
Handle unknown values using “@unknown default”
假如接受修正主张,则代码如下
let axis: UIUserInterfaceSizeClass = .unspecified
switch axis {
case .unspecified:
fallthrough
case .regular:
fallthrough
case .compact:
print("")
@unknown default:
fatalError()
}
为什么引入@unknown default
由于Swift要求switch case有必要exhausitive,为了满足该要求,在Swift 4及曾经,咱们运用switch case来进行枚举时,通常只要两种写法:
- 枚举一切case
- 枚举部分case,最后运用default掩盖其他case
但这两种状况都存在各自的问题:
当未来某个版本中,枚举的提供者新增了一个case,那么
- 假如之前运用枚举时枚举了一切case,则会编译犯错,由于不满足exhausitive规矩
- 假如运用default掩盖了一切case,虽然不会编译犯错,但由于未对新增的case进行处理,事务逻辑上或许存在潜在的危险
@unknown default
就是用来解决该上面问题的,它其实就做了一件工作:
- 当运用了
@unknown default
,但并没有枚举一切case时,编译器会给出未满足exhausitive的正告,而非像“default`那样编译错误
这直接带来的好处是:
- 当运用
@unknown default
一起现已枚举了一切case时,当后续枚举提供者新增了case,不会由于编译犯错 - 一起鼓励开发者运用
@unknown default
代替原来的default
,这样后续新增或删减case时,编译器会及时提示开发者针对enum的变化做必要的调整
一句话总结该特点的意图
既做到不影响开发者源码的可编译性,又能及时提示开发者做好兼容适配工作
留意,该特点现在并不适用一切的enum,具体看下一小节
@unknown default
适用范围
现在仅适用于:
- C中的enum
- 来自体系库入
UIKit
、Swift Standard Library
中的enum
未来或许会允许开发者自己开发的Library,但现在不适用
我列举了Enum一切或许得状况,对上述适用范围进行了验证
- 在自己工程中界说了C Enum–ProjectSourceTestEnumType
- 在第三方库MJRefresh(OC编写)中界说了C Enum–MJTestEnumType
- 在SnapKit(Swift 编写)中添加了一个Swift自界说Enum–SnapKitTestEnum
func testEnumForCEnum(_ testEnum: MJTestEnumType) {
switch testEnum { // Compiler Warning: Switch covers known cases, but 'MJTestEnumType' may have additional unknown values
case .type1: print("")
case .type2: print("")
}
}
func testEnumForStandardLibrary(_ axis: UIUserInterfaceSizeClass) {
switch axis { // Compilier Warning: Switch covers known cases, but 'UIUserInterfaceSizeClass' may have additional unknown values, possibly added in future versions
case .unspecified: print("")
case .regular: print("")
case .compact: print("")
}
}
func testEnumForProjectCEnum(_ testEnum: ProjectSourceTestEnumType) {
switch testEnum { // Compiler Warning: Switch covers known cases, but 'ProjectSourceTestEnumType' may have additional unknown values
case .type1: print("")
case .type2: print("")
}
}
func testEnumForThirdLibrary(_ testEnum: SnapKitTestEnum) {
switch testEnum { // 无正告
case .case1: print("")
case .case2: print("")
}
}
为什么限定适用范围呢
来自官方的解释是
该特性首要适用对象并非enum in project source code,而是project所依赖的enum in library code。说白了就是给代码库开发人员的
- 之所以运用C Enum,是由于C Enum处理起来有点复杂,没办法区别一个C Enum归于project code仍是library code,所以进行了一致处理
什么是Frozen enum
到此还没有完毕,试想一下,假如一切iOS的体系库中的枚举都运用如上规矩,那是不是就相当于主张iOS开发者在后续一切进行枚举时都添加@unknown default
呢
似乎不太合理。所以引入了Frozen or non Frozen enum的概念,Frozen enum的写法如下所示
@frozen public enum SnapKitTestFrozenEnum {
case case1
case case2
}
typedef NS_CLOSED_ENUM(NSUInteger, MJTestClosedEnumType) {
MJTestClosedEnumType1,
MJTestClosedEnumType2
};
- 此时再去枚举上面enum的时分,及时不写
@unknown default
,也不会有正告了 - 一起,当library的开发者假如真的往frozen enum中添加了一个case,咱们接入后编译器会再次报错,奉告违反了exhausitive规矩
frozen是冻住的意思,表明不会再改动,比如体系库中的NSComparisonResult
,比较成果只要大、小和持平三种状况,打死也不会出现第三种了,这种就可以标记为frozen了
typedef NS_CLOSED_ENUM(NSInteger, NSComparisonResult) {
NSOrderedAscending = -1L,
NSOrderedSame,
NSOrderedDescending
};
当然,现在大部分枚举还都是non frozen的
总结
留意@unknown default
的适用范围:
一切代码中的C Enum和体系库代码中的Swift或OC编写的enum
参考
- Swift 5 Frozen enums