添加新枚举值时的切换行为

Switch behavior when new enum values are added

注意:这不再相关。 Swift 的最新版本具有多项功能,以各种方式解决枚举二进制兼容性问题,例如 @unknown default、冻结枚举等。

HealthKit 中的各种枚举往往会在 iOS 的每个版本中添加新值。例如,HKWorkoutActivityType 自推出以来在每个 iOS 版本中都添加了新值。

假设我使用 Swift switch 语句将此枚举映射到字符串值:

extension HKWorkoutActivityType {
    var displayName: String {
        switch self {
            case .americanFootball: return "American Football"
            // ...Exhaustive switch statement, with a line for every enum case.
            // Including values added in iOS 10 and 11...
            case .taiChi: return "Tai Chi"
        }
    }
}

let event: HKWorkoutEvent = ...
print("Activity type is: \(event.type.displayName)")

此 switch 语句针对 iOS 11 SDK 编译,工作正常并且向后兼容旧 iOS 版本。注意在编译的时候switch语句是穷尽的,所以没有default的情况。

但是如果在 iOS 12 中添加了新的 HKWorkoutActivityType 值,并且我没有重新编译此代码,那么 displayName getter 将如何处理新的枚举值?我应该期待崩溃吗?未定义的行为?它是否取决于枚举的类型(例如,这里是 Objective-C NS_ENUM,但 Swift 枚举的行为是否不同)?等等

非常 有趣的问题,已投票。我知道没有办法 完美地 在 (a) Xcode 9 和 (b) iOS 11 中测试它。但这可能是你的答案。

我认为想要的解决方案如果if #available(iOS 12, *)存在问题。封装整个switch语句?只是 iOS 12 的加法?

结果应该是Xcode中的目标iOS版本和Swift编译器之间的结果,它被覆盖了——并且应该产生一个错误(希望能解释 iOS 11 是目标但某些东西仅在 iOS 12 中可用的问题)表明您需要在某个地方使用 (a) if #available(iOS 12, *) 或更改您的目标.

不过,我知道没有简单的方法可以在不重建的情况下进行测试。这对你的问题是不可或缺的!因此我猜规则是:

总是在发布新的 iOS(和关联的 Xcode)版本时重建您的应用程序。

考虑这部分的你拥有你的代码。

FWIW,这是 this Swift Evolution proposal 正在解决的部分问题。 希望他们也能决定一个能够很好地解决此类问题的解决方案!

长话短说,您可以通过添加默认情况(即使编译器会对您大喊大叫)或使用版本标签来避免此问题。然而,这个问题目前可能属于 "undefined"。

长话短说:

Swift 的当前版本没有 ABI 稳定性,因此编译的 Swift 应用程序 不保证 (几乎肯定不会)接口使用更新版本编译的框架(平台框架仍然 Objective-C 的原因)。

因此,此类更改如何影响 Swift 尚待研究。当 Swift 5 发布时,我们可能会对如何处理此类问题有更好的定义。在那之前添加默认 and/or 版本检查可能是可行的方法。