Xcode 9和Xcode 10在相同的Swift版本下产生不同的结果
Xcode 9和Xcode 10在相同的Swift版本下产生不同的结果
我在xcode 9.3和xcode 10 beta 3 playground中运行此代码
import Foundation public protocol EnumCollection: Hashable { static func cases() -> AnySequence } public extension EnumCollection { public static func cases() -> AnySequence { return AnySequence { () -> AnyIterator 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
我完全不理解这个。
以下是适用于 Xcode 10 和 Swift 4.2 及以上版本的解决方案。
步骤 1:创建 Protocol EnumIterable。
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:将 EnumIterator Protocol 扩展到您的枚举。
enum Colors: String, EnumIterable { case red = "Red" case yellow = "Yellow" case blue = "Blue" case green = "Green" }
步骤 3:像使用 hashValue 一样使用 indexValue 属性。
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)")
输出:"Index Value: 0, Raw Value: Red, Hash Value: 1593214705812839748"
print("Index Value: \(Colors.yellow.indexValue), Raw Value: \(Colors.yellow.rawValue), Hash Value: \(Colors.yellow.hashValue)")
输出:"Index Value: 1, Raw Value: Yellow, Hash Value: -6836447220368660818"
print("Index Value: \(Colors.blue.indexValue), Raw Value: \(Colors.blue.rawValue), Hash Value: \(Colors.blue.hashValue)")
输出:"Index Value: 2, Raw Value: Blue, Hash Value: -8548080225654293616"
print("Index Value: \(Colors.green.indexValue), Raw Value: \(Colors.green.rawValue), Hash Value: \(Colors.green.hashValue)")
输出:"Index Value: 3, Raw Value: Green, Hash Value: 6055121617320138804"
这是一种未记录的获取所有枚举值序列的方式,只有在较早的Swift版本中偶然有效。它依赖于枚举值的哈希值为连续整数,从零开始。
但在Swift 4.2中(即使在Swift 4兼容模式下运行),这种方式已经不再有效,因为哈希值现在始终是随机的,详情请参见SE-0206哈希增强功能:
为了使哈希值不那么可预测,默认情况下,标准哈希函数使用每个执行的随机种子。
你可以通过以下方式验证:
print(NumberEnum.one.hashValue) print(NumberEnum.two.hashValue)
在Xcode 10中,它不会输出0
和1
,而是一些其他的值,每次程序运行时也会变化。
对于一个合适的Swift 4.2/Xcode 10解决方案,请参见如何枚举具有String类型的枚举?:
extension NumberEnum: CaseIterable { } print(Array(NumberEnum.allCases).count) // 4