Xcode 9 和 Xcode 10 给出不同的结果,即使 swift 版本相同
Xcode 9 and Xcode 10 giving different results, even with same swift version
我在 xcode 9.3 和 xcode 10 beta 3 playground运行 中都是此代码
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) { [=13=].withMemoryRebound(to: self, capacity: 1) { [=13=].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(即使 运行ning
在 Swift 4 兼容模式下)因为散列值现在总是
随机化,参见 SE-0206 Hashable Enhancements:
To make hash values less predictable, the standard hash function uses a per-execution random seed by default.
您可以通过
验证
print(NumberEnum.one.hashValue)
print(NumberEnum.two.hashValue)
不 打印 0
和 1
与 Xcode 10,但一些
其他值也因每个程序而异 运行.
有关 Swift 4.2/Xcode 10 的正确解决方案,请参阅 How to enumerate an enum with String type?:
extension NumberEnum: CaseIterable { }
print(Array(NumberEnum.allCases).count) // 4
针对 Xcode 10 和 Swift 4.2 及更高版本的解决方案如下。
步骤 1: 创建协议 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 协议扩展到您的枚举。
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"
如果您使用枚举的 hashValue 来确定 case 值(位置或 id),这是一种错误的方法,因为它不能保证 return 连续的 int 值,0,1,2...从 swift 4.2
开始不再工作
例如,如果您使用这样的枚举:
enum AlertResultType {
case ok, cancel
}
此枚举的 hashValue 可能 return 一个大的 int 值而不是 0(确定)和 1(取消)。
因此您可能需要更准确地声明枚举类型并使用rowValue。例如
enum AlertResultType : Int {
case ok = 0, cancel = 1
}
我在 xcode 9.3 和 xcode 10 beta 3 playground运行 中都是此代码
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) { [=13=].withMemoryRebound(to: self, capacity: 1) { [=13=].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(即使 运行ning 在 Swift 4 兼容模式下)因为散列值现在总是 随机化,参见 SE-0206 Hashable Enhancements:
To make hash values less predictable, the standard hash function uses a per-execution random seed by default.
您可以通过
验证print(NumberEnum.one.hashValue)
print(NumberEnum.two.hashValue)
不 打印 0
和 1
与 Xcode 10,但一些
其他值也因每个程序而异 运行.
有关 Swift 4.2/Xcode 10 的正确解决方案,请参阅 How to enumerate an enum with String type?:
extension NumberEnum: CaseIterable { }
print(Array(NumberEnum.allCases).count) // 4
针对 Xcode 10 和 Swift 4.2 及更高版本的解决方案如下。
步骤 1: 创建协议 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 协议扩展到您的枚举。
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"
如果您使用枚举的 hashValue 来确定 case 值(位置或 id),这是一种错误的方法,因为它不能保证 return 连续的 int 值,0,1,2...从 swift 4.2
开始不再工作例如,如果您使用这样的枚举:
enum AlertResultType {
case ok, cancel
}
此枚举的 hashValue 可能 return 一个大的 int 值而不是 0(确定)和 1(取消)。
因此您可能需要更准确地声明枚举类型并使用rowValue。例如
enum AlertResultType : Int {
case ok = 0, cancel = 1
}