[译] Swift 5 中的枚举冻结

你是否已经将你的 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

additional unknown values warning

警告内容: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 有别的可能值?

咱们须要作什么?

  • 首先,你不须要改变你本身原先的 Swift 枚举。当你升级到 Swift 5 时,你不须要一开始就手动在代码上添加 @unknown default:。Xcode 会发出警告来提示你须要添加的位置。
  • 此更改仅适用于标准库和其余框架中的 C 语言枚举。
  • 若是您的 switch 包含 default: case,那就不须要进行任何变化。
  • 完全切换 C 语言的非冻结枚举,包括全部已知的状况(不含 default:)是 Swift 5 中的警告。
  • 你可让 Xcode 帮你自动修复代码,它会添加一个 @unknown: 的 case 并消除警告。

阅读更多

有关更多详细信息,请参阅 Swift 进化的提案:

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索