添加新枚举值时切换行为

时间:2018-01-16 19:06:09

标签: swift health-kit

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)")

这个针对iOS 11 SDK编译的switch语句运行良好,并且向后兼容旧的iOS版本。请注意,在编译时,switch语句是详尽的,因此没有default个案例。

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

2 个答案:

答案 0 :(得分:1)

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

简而言之,您可以通过添加默认情况(即使编译器会对您大喊大叫)或使用版本标记来避免此问题。但是,这个问题目前可能属于“未定义”。

长篇故事:

当前版本的Swift没有ABI稳定性,因此编译后的Swift应用程序不能保证(并且几乎肯定不会)与使用较新版本编译的Framework接口(平台之所以框架仍然是Objective-C)。

因此,这类变化对Swift的影响是一项正在进行的工作。当Swift 5发布时,我们可能会更好地定义如何处理这类问题。直到那时添加默认和/或版本检查可能是最佳选择。

答案 1 :(得分:0)

非常有趣的问题,并且投了赞成票。我知道在(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)版本时,请始终重建您的应用。

请考虑你们这部分人对你的代码拥有所有权。