Xcode 9 和 Xcode 10 给出不同的结果,即使使用相同的 swift 版本也是如此



我在 xcode 9.3 和 xcode 10 beta 3 操场上运行此代码

import Foundation
public protocol EnumCollection: Hashable {
static func cases() -> AnySequence<Self>
}
public extension EnumCollection {
public static func cases() -> AnySequence<Self> {
return AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
}
}
}
enum NumberEnum: EnumCollection{
case one, two, three, four
}
Array(NumberEnum.cases()).count

即使两者都使用 Swift 4.1,他们也给了我不同的结果

Xcode 9.3上,数组的大小为4

Xcode 10 beta 3上 数组的大小为0

我完全不明白这一点。

这是一种获取所有枚举值序列的未记录方法, 并且只是偶然地与早期的 Swift 版本一起工作。它依赖于 枚举值的哈希值是连续的整数, 从零开始。

这绝对不适用于 Swift 4.2(即使运行 在 Swift 4 兼容模式下(,因为哈希值现在始终 随机,请参阅 SE-0206 哈希增强功能:

为了使哈希值更不可预测,标准哈希函数默认使用每次执行的随机种子。

您可以使用

print(NumberEnum.one.hashValue)
print(NumberEnum.two.hashValue)

它不会使用 Xcode 10 打印01,但有些 其他值也随每个程序运行而变化。

有关正确的 Swift 4.2/Xcode 10 解决方案,请参阅如何使用字符串类型枚举枚举?:

extension NumberEnum: CaseIterable  { }
print(Array(NumberEnum.allCases).count) // 4

对于Xcode 10 和 Swift 4.2 及更高版本,解决方案如下。

步骤 1:创建可枚举的协议。

protocol EnumIterable: RawRepresentable, CaseIterable {
var indexValue: Int { get }
}
extension EnumIterable where Self.RawValue: Equatable {
var indexValue: Int {
var index = -1
let cases = Self.allCases as? [Self] ?? []
for (caseIndex, caseItem) in cases.enumerated() {
if caseItem.rawValue == self.rawValue {
index = caseIndex
break
}
}
return index
}
}

步骤 2:将枚举器协议扩展到枚举。

enum Colors: String, EnumIterable {
case red = "Red"
case yellow = "Yellow"
case blue = "Blue"
case green = "Green"
}

第 3 步:使用 indexValue 属性,就像使用 hashValue 一样。

Colors.red.indexValue
Colors.yellow.indexValue
Colors.blue.indexValue
Colors.green.indexValue

示例打印语句和输出

print("Index Value: (Colors.red.indexValue), Raw Value: (Colors.red.rawValue), Hash Value: (Colors.red.hashValue)")

输出:"索引值:0,原始值:红色,哈希值:1593214705812839748">

print("Index Value: (Colors.yellow.indexValue), Raw Value: (Colors.yellow.rawValue), Hash Value: (Colors.yellow.hashValue)")

输出:"索引值:1,原始值:黄色,哈希值:-6836447220368660818">

print("Index Value: (Colors.blue.indexValue), Raw Value: (Colors.blue.rawValue), Hash Value: (Colors.blue.hashValue)")

输出:"索引值:2,原始值:蓝色,哈希值:-8548080225654293616">

print("Index Value: (Colors.green.indexValue), Raw Value: (Colors.green.rawValue), Hash Value: (Colors.green.hashValue)") 

输出:"索引值:3,原始值:绿色,哈希值:6055121617320138804">

如果您使用枚举的 hashValue 来确定大小写值(位置或 id(,这是一种错误的方法,因为它不能保证返回连续的整数值 0,1,2...从 swift 4.2 开始它不再工作

例如,如果您使用这样的枚举:

enum AlertResultType {
case ok, cancel 
}

此枚举的 hashValue 可能会返回一个大的 int 值,而不是 0(确定(和 1(取消(。

因此,您可能需要更精确地声明枚举类型并使用 rowValue。例如

enum AlertResultType : Int {
case ok = 0, cancel = 1
}

最新更新