Xcode 9和Xcode 10在相同的Swift版本下产生不同的结果

15 浏览
0 Comments

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

我完全不理解这个。

admin 更改状态以发布 2023年5月23日
0
0 Comments

以下是适用于 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"

0
0 Comments

这是一种未记录的获取所有枚举值序列的方式,只有在较早的Swift版本中偶然有效。它依赖于枚举值的哈希值为连续整数,从零开始。

但在Swift 4.2中(即使在Swift 4兼容模式下运行),这种方式已经不再有效,因为哈希值现在始终是随机的,详情请参见SE-0206哈希增强功能

为了使哈希值不那么可预测,默认情况下,标准哈希函数使用每个执行的随机种子。

你可以通过以下方式验证:

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

在Xcode 10中,它不会输出01,而是一些其他的值,每次程序运行时也会变化。

对于一个合适的Swift 4.2/Xcode 10解决方案,请参见如何枚举具有String类型的枚举?

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

0