如何确定Swift enum中的案例数?

(我希望避免手动枚举所有值,或者如果可能的话使用旧的“enum_count技巧”。)


当前回答

如果你不想在最后一个枚举中创建你的代码,你可以在枚举中创建这个函数。

func getNumberOfItems() -> Int {
    var i:Int = 0
    var exit:Bool = false
    while !exit {
        if let menuIndex = MenuIndex(rawValue: i) {
            i++
        }else{
            exit = true
        }
    }
    return i
}

其他回答

我写了一个简单的扩展,它给所有枚举的原始值是整数一个count属性:

extension RawRepresentable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

不幸的是,它给了计数属性OptionSetType,它不会正常工作,所以这里是另一个版本,需要显式符合CaseCountable协议的任何枚举的情况下,你想要计数:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

它与Tom Pelaia发布的方法非常相似,但适用于所有整数类型。

我有一篇博客文章详细介绍了这一点,但只要你的枚举的原始类型是一个整数,你可以这样添加一个计数:

enum Reindeer: Int {
    case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
    case Rudolph

    static let count: Int = {
        var max: Int = 0
        while let _ = Reindeer(rawValue: max) { max += 1 }
        return max
    }()
}

或者你可以在枚举之外定义_count,并静态地附加它:

let _count: Int = {
    var max: Int = 0
    while let _ = EnumName(rawValue: max) { max += 1 }
    return max
}()

enum EnumName: Int {
    case val0 = 0
    case val1
    static let count = _count
}

这样,不管你创建了多少个枚举,它只会被创建一次。

(如果是静态的,就删除这个答案)

以下方法来自CoreKit,与其他人建议的答案相似。这适用于Swift 4。

public protocol EnumCollection: Hashable {
    static func cases() -> AnySequence<Self>
    static var allValues: [Self] { get }
}

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
            }
        }
    }

    public static var allValues: [Self] {
        return Array(self.cases())
    }
}

enum Weekdays: String, EnumCollection {
    case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}

然后你只需要调用weekdays。allvalues。count。

这是次要的,但我认为一个更好的O(1)解决方案将是以下(只有当你的enum是Int从x开始,等等):

enum Test : Int {
    case ONE = 1
    case TWO
    case THREE
    case FOUR // if you later need to add additional enums add above COUNT so COUNT is always the last enum value 
    case COUNT

    static var count: Int { return Test.COUNT.rawValue } // note if your enum starts at 0, some other number, etc. you'll need to add on to the raw value the differential 
}

我仍然认为当前选择的答案是所有枚举的最佳答案,除非您正在使用Int,否则我推荐这个解决方案。