如何获取所有枚举值作为数组


99

我有以下列举。

enum EstimateItemStatus: Printable {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending: return "Pending"
        case .OnHold: return "On Hold"
        case .Done: return "Done"
        }
    }

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

我需要将所有原始值获取为字符串数组(例如["Pending", "On Hold", "Done"])。

我将此方法添加到枚举中。

func toArray() -> [String] {
    var n = 1
    return Array(
        GeneratorOf<EstimateItemStatus> {
            return EstimateItemStatus(id: n++)!.description
        }
    )
}

但我收到以下错误。

找不到类型'GeneratorOf'的初始化程序,该初始化程序接受类型'(()-> _)'的参数列表

有没有更简单,更好或更优雅的方式来做到这一点?


2
您可以创建类似let array的数组:[EstimateItemStatus] = [.Pending,.Onhold,.Done]
Kristijan Delivuk

1
@KristijanDelivuk我想将此功能添加到枚举本身。因此,如果我向枚举添加另一个值,则不必去在代码库其他位置的任何地方添加它。
Isuru 2015年


我有一个答案,您可以在这里参考stackoverflow.com/a/48960126/5372480
MSimic '18年

Answers:


146

对于Swift 4.2(Xcode 10)及更高版本

有一个CaseIterable协议:

enum EstimateItemStatus: String, CaseIterable {
    case pending = "Pending"
    case onHold = "OnHold"
    case done = "Done"

    init?(id : Int) {
        switch id {
        case 1: self = .pending
        case 2: self = .onHold
        case 3: self = .done
        default: return nil
        }
    }
}

for value in EstimateItemStatus.allCases {
    print(value)
}

对于Swift <4.2

不,您无法查询enum包含的值。看到这篇文章。您必须定义一个列出所有值的数组。另请参阅“ 如何将所有枚举值作为数组获取 ”中的Frank Valbuena解决方案。

enum EstimateItemStatus: String {
    case Pending = "Pending"
    case OnHold = "OnHold"
    case Done = "Done"

    static let allValues = [Pending, OnHold, Done]

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

for value in EstimateItemStatus.allValues {
    print(value)
}

请参阅以下答案:stackoverflow.com/a/28341290/8047(包括Swift 3代码)。
Dan Rosenstark '16

3
支持allValues部分,但不确定使用String枚举并用Int初始化的枚举的感觉。
Tyress

第一个链接已断开,但现在似乎在exceptionshub.com/…
锡人

39

Swift 4.2引入了一个新协议,名为CaseIterable

enum Fruit : CaseIterable {
    case apple , apricot , orange, lemon
}

当您符合时,您可以从enum类似的情况中获得一个数组

for fruit in Fruit.allCases {
    print("I like eating \(fruit).")
}

25

CaseIterable协议添加到枚举:

enum EstimateItemStatus: String, CaseIterable {
    case pending = "Pending"
    case onHold = "OnHold"
    case done = "Done"
}

用法:

let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue }
//["Pending", "OnHold", "Done"]

17

还有另一种方法,至少在编译时是安全的:

enum MyEnum {
    case case1
    case case2
    case case3
}

extension MyEnum {
    static var allValues: [MyEnum] {
        var allValues: [MyEnum] = []
        switch (MyEnum.case1) {
        case .case1: allValues.append(.case1); fallthrough
        case .case2: allValues.append(.case2); fallthrough
        case .case3: allValues.append(.case3)
        }
        return allValues
    }
}

请注意,这适用于任何枚举类型(RawRepresentable与否),并且如果您添加新的大小写,则将得到一个编译器错误,这是很好的,因为它将强制您使此更新。


1
非正统的,但是它可以工作,并且如果您修改枚举大小写,它会警告您。聪明的解决方案!
Chuck Krutsinger

12

我在某处找到以下代码:

protocol EnumCollection : Hashable {}


extension EnumCollection {

    static func cases() -> AnySequence<Self> {
        typealias S = Self
        return AnySequence { () -> AnyIterator<S> in
            var raw = 0
            return AnyIterator {
                let current : Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee }
                }
                guard current.hashValue == raw else { return nil }
                raw += 1
                return current
            }
        }
    }
}

用:

enum YourEnum: EnumCollection { //code }

YourEnum.cases()

从YourEnum返回案例列表


似乎是一个很好的解决方案,但对斯威夫特4.不少编译错误
Isuru

1
“某处”可能是:theswiftdev.com/2017/10/12/swift-enum-all-values(还有其他吗?)。博主称赞CoreKit
AmitaiB '18

5
这会破坏XCode 10(无论Swift版本如何),因为枚举的hashValue不再是增量,而是随机的,从而破坏了该机制。新的方式做,这是升级到4.2雨燕和使用CaseIterable
Yasper

8

要获取出于功能目的的列表,请使用EnumName.allCases返回数组的表达式,例如

EnumName.allCases.map{$0.rawValue} 

给定一个字符串列表 EnumName: String, CaseIterable

注意:使用allCases代替AllCases()


8
enum EstimateItemStatus: String, CaseIterable {
  case pending = "Pending"
  case onHold = "OnHold"
  case done = "Done"

  static var statusList: [String] {
    return EstimateItemStatus.allCases.map { $0.rawValue }
  }
}

[“待处理”,“保留”,“完成”]


2

Swift 5更新

我发现最简单的解决方案是.allCases在扩展的枚举上使用CaseIterable

enum EstimateItemStatus: CaseIterable {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending: return "Pending"
        case .OnHold: return "On Hold"
        case .Done: return "Done"
        }
    }

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

.allCases在任何CaseIterable枚举上将返回Collection该元素的一个。

var myEnumArray = EstimateItemStatus.allCases

有关CaseIterable的更多信息


无需实现description()。只需将每种情况等同于字符串,例如case OnHold = "On Hold",这将成为每种情况的原始值。
pnizzle '19

@pnizzle我知道,它在那里,因为它在原始问题中。
克里斯托弗·拉森

1

对于Swift 2

// Found http://stackoverflow.com/questions/24007461/how-to-enumerate-an-enum-with-string-type
func iterateEnum<T where T: Hashable, T: RawRepresentable>(_: T.Type) -> AnyGenerator<T> {
    var i = 0
    return AnyGenerator {
        let next = withUnsafePointer(&i) {
            UnsafePointer<T>($0).memory
        }
        if next.hashValue == i {
            i += 1
            return next
        } else {
            return nil
        }
    }
}

func arrayEnum<T where T: Hashable, T: RawRepresentable>(type: T.Type) -> [T]{
    return Array(iterateEnum(type))
}

要使用它:

arrayEnum(MyEnumClass.self)

为什么元素会hashValue0..n
NRitH'7

1

经过Sequence和小时尝试n错误的启发。我终于在Xcode 9.1上获得了这种舒适漂亮的Swift 4方法:

protocol EnumSequenceElement: Strideable {
    var rawValue: Int { get }
    init?(rawValue: Int)
}

extension EnumSequenceElement {
    func distance(to other: Self) -> Int {
        return other.rawValue - rawValue
    }

    func advanced(by n: Int) -> Self {
        return Self(rawValue: n + rawValue) ?? self
    }
}

struct EnumSequence<T: EnumSequenceElement>: Sequence, IteratorProtocol {
    typealias Element = T

    var current: Element? = T.init(rawValue: 0)

    mutating func next() -> Element? {
        defer {
            if let current = current {
                self.current = T.init(rawValue: current.rawValue + 1)
            }
        }
        return current
    }
}

用法:

enum EstimateItemStatus: Int, EnumSequenceElement, CustomStringConvertible {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending:
            return "Pending"
        case .OnHold:
            return "On Hold"
        case .Done:
            return "Done"
        }
    }
}

for status in EnumSequence<EstimateItemStatus>() {
    print(status)
}
// Or by countable range iteration
for status: EstimateItemStatus in .Pending ... .Done {
    print(status)
}

输出:

Pending
On Hold
Done

1

您可以使用

enum Status: Int{
    case a
    case b
    case c

}

extension RawRepresentable where Self.RawValue == Int {

    static var values: [Self] {
        var values: [Self] = []
        var index = 1
        while let element = self.init(rawValue: index) {
            values.append(element)
            index += 1
        }
        return values
    }
}


Status.values.forEach { (st) in
    print(st)
}

真好!从Swift 3.2升级到4.1之后,这就是我使用的解决方案。我们最初有AnyItertor <Self>声明。您的解决方案更加简洁易读。谢谢!
尼克N

2
不过这里有一个代码缺陷。它错过了案件的第一项。将var index = 1更改为var index = 0
Nick N

0

如果枚举是增量枚举并与数字关联,则可以使用映射到枚举值的数字范围,如下所示:

// Swift 3
enum EstimateItemStatus: Int {
    case pending = 1,
    onHold
    done
}

let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }

这不适用于与字符串或数字以外的任何东西关联的枚举,但是如果是这样,它将非常有用!


0

扩展枚举以创建allValues。

extension RawRepresentable where Self: CaseIterable {
      static var allValues: [Self.RawValue] {
        return self.allCases.map { $0.rawValue}
      }
    }

尽管此代码可以为OP的问题提供解决方案,但强烈建议您提供有关此代码为何和/或如何回答问题的其他上下文。从长远来看,只有代码的答案通常变得毫无用处,因为遇到类似问题的未来观看者将无法理解解决方案背后的原因。
E. Zeytinci
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.