如何确定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
}

其他回答

它可以使用一个静态常量,其中包含枚举的最后一个值加1。

enum Color : Int {
    case  Red, Orange, Yellow, Green, Cyan, Blue, Purple

    static let count: Int = Color.Purple.rawValue + 1

    func toUIColor() -> UIColor{
        switch self {
            case .Red:
                return UIColor.redColor()
            case .Orange:
                return UIColor.orangeColor()
            case .Yellow:
                return UIColor.yellowColor()
            case .Green:
                return UIColor.greenColor()
            case .Cyan:
                return UIColor.cyanColor()
            case .Blue:
                return UIColor.blueColor()
            case .Purple:
                return UIColor.redColor()
        }
    }
}

或者你可以在枚举之外定义_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
}

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

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

如果实现不反对使用整数enum,你可以添加一个额外的成员值Count来表示枚举中的成员数量-参见下面的例子:

enum TableViewSections : Int {
  case Watchlist
  case AddButton
  case Count
}

现在,您可以通过调用TableViewSections.Count.rawValue来获取枚举中的成员数量,在上面的例子中,它将返回2。

当你在switch语句中处理枚举时,确保在遇到Count成员时抛出断言失败:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  let currentSection: TableViewSections = TableViewSections.init(rawValue:section)!
  switch(currentSection) {
  case .Watchlist:
    return watchlist.count
  case .AddButton:
    return 1
  case .Count:
    assert(false, "Invalid table view section!")
  }
}

以下方法来自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。

对于我的用例,在一个代码库中,多人可以向一个枚举添加键,这些情况都应该在allKeys属性中可用,重要的是要根据枚举中的键验证allKeys。这是为了避免有人忘记将他们的密钥添加到所有密钥列表。将allKeys数组的计数(首先作为一个集合创建,以避免被欺骗)与枚举中的键数量相匹配,可确保它们都存在。

上面的一些答案显示了在Swift 2中实现这一点的方法,但在Swift 3中没有任何方法。以下是Swift 3的格式化版本:

static func enumCount<T: Hashable>(_ t: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(to: &i) {
      $0.withMemoryRebound(to:t.self, capacity:1) { $0.pointee.hashValue != 0 }
    }) {
      i += 1
    }
    return i
}

static var allKeys: [YourEnumTypeHere] {
    var enumSize = enumCount(YourEnumTypeHere.self)

    let keys: Set<YourEnumTypeHere> = [.all, .your, .cases, .here]
    guard keys.count == enumSize else {
       fatalError("Missmatch between allKeys(\(keys.count)) and actual keys(\(enumSize)) in enum.")
    }
    return Array(keys)
}

根据您的用例,您可能希望只在开发中运行测试,以避免在每个请求上使用allKeys的开销