如何获得所有枚举值作为一个数组

我有以下枚举。

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’的初始化器,该类型接受类型为’(()-> _)’的参数列表

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

99110 次浏览

适用于 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包含什么值。见 这篇文章。您必须定义一个列出所有值的数组。还可以在“ 如何获得所有枚举值作为一个数组”中查看弗兰克 · 瓦尔布埃纳的解决方案。

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

为了 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)

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

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


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

对于与字符串或数字以外的任何东西相关联的枚举,这种方法并不能很好地工作,但是如果是这种情况,那么它就非常好用!

我在某个地方发现了这个代码:

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 的退回案件清单

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

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

注意,这适用于任何枚举类型(无论是否为 RawRepenable) ,如果您添加了一个新的用例,那么您将得到一个编译器错误,这是好的,因为将强制您更新这个。

经过从 顺序的灵感和小时的尝试 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

你可以使用

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 4.2 引入了一个名为 CaseIterable的新协议

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

当您符合以下条件时,您可以从 enum例子中获得一个数组,如下所示

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

Swift 5

可以缓刑协议添加到枚举:

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

用法:

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

为了获得用于函数目的列表,可以使用返回数组的表达式 EnumName.allCases

EnumName.allCases.map{$0.rawValue}

将给出给定 EnumName: String, CaseIterable的字符串列表

注意: 使用 allCases代替 AllCases()

Swift 5的更新

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

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

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

var myEnumArray = EstimateItemStatus.allCases

更多关于 可以缓刑的信息

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


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

[“等待”,“等待”,“完成”]

对枚举进行扩展以创建 allValue。

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