获取所有enum值作为数组

时间:2022-09-21 12:42:25

I have the following enum.

我有下面的enum。

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

I need to get all the raw values as an array of strings (like so ["Pending", "On Hold", "Done"]).

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

I added this method to the enum.

我将此方法添加到enum。

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

But I'm getting the following error.

但是我得到了下面的错误。

Cannot find an initializer for type 'GeneratorOf' that accepts an argument list of type '(() -> _)'

无法找到类型'GeneratorOf'的初始化器,该初始化器接受类型'()-> _)'的参数列表

I can't figure out how to resolve this. Any help? Or please tell me if there is an easier/better/more elegant way to do this.

我想不出怎么解决这个问题。任何帮助吗?或者请告诉我是否有更简单/更好/更优雅的方法来做这件事。

Thank you.

谢谢你!

9 个解决方案

#1


8  

I found somewhere this code:

我在什么地方找到了这个密码:

protocol EnumCollection : Hashable {}


extension EnumCollection {

    static func cases() -> AnySequence<Self> {
        typealias S = Self
        return AnySequence { () -> AnyGenerator<S> in
            var raw = 0
            return AnyGenerator {
                let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory }
                guard current.hashValue == raw else { return nil }
                raw += 1
                return current
            }
        }
    }
}

Use:

使用:

enum YourEnum: EnumCollection { //code }

YourEnum.cases()

return list of cases from YourEnum

从YourEnum返回病例列表

#2


16  

For Swift 4.2 (Xcode 10) and later

There's a CaseIterable protocol:

有一个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)
}

For Swift < 4.2

No, you can't query an enum for what values it contains. See this article. You have to define an array that list all the values you have:

不,您不能查询枚举包含的值。看到这篇文章。你必须定义一个列有所有值的数组:

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

#3


9  

There's another way that at least is safe at compile time:

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

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

Notice that this works for any enum type (RawRepresentable or not) and also if you add a new case then you will get a compiler error which is good since will force you to have this up to date.

请注意,这适用于任何enum类型(RawRepresentable或not),而且如果您添加一个新案例,那么您将会得到一个编译器错误,这很好,因为它将迫使您更新此内容。

#4


3  

Swift 4.2 introduces a new protocol named CaseIterable

Swift 4.2引入了一种名为CaseIterable的新协议

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

that when you conforms to , you can get an array from the enum cases like this

当你遵守时,你可以从enum实例中获得一个数组,就像这样

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

#5


2  

For Swift 2

斯威夫特2

// Found http://*.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))
}

To use it:

使用它:

arrayEnum(MyEnumClass.self)

#6


1  

After inspiration from Sequence and hours of try n errors. I finally got this comfortable and beautiful Swift 4 way on Xcode 9.1:

从序列和数小时的尝试中获得灵感。我终于在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
    }
}

Usage:

用法:

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

Output:

输出:

Pending
On Hold
Done

#7


0  

If your enum is incremental and associated with numbers, you can use range of numbers that you map to enum values, like so:

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

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

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

This doesn't quite work with enums associated with strings or anything other than numbers, but it works great if that is the case!

这并不完全适用于与字符串或除数字之外的任何东西相关的枚举,但如果是这样的话,它将非常有效!

#8


0  

Details

Xcode 9.1, Swift 4

Xcode 9.1,斯威夫特4

Solution

protocol EnumIterator {
    static func getItem(at index: Int) -> Self?
}

extension Array where Element: EnumIterator {

    static var all: [Element] {
        var result = [Element]()
        var index = 0
        while true {
            if let item = Element.getItem(at: index) {
                result.append(item)
                index += 1
            } else {
                break
            }
        }
        return result
    }
}

Usage

enum

枚举

enum Enum: EnumIterator  {
    case val1, val2, val3

    static func getItem(at index: Int) -> Enum? {
        switch index {
        case 0: return .val1
        case 1: return .val2
        case 2: return .val3
        default: return nil
        }
    }
}

Array with all enum values

具有所有枚举值的数组

 let array = [Enum].all

Full sample

Do not forget to insert the solution code here

不要忘记在这里插入解决方案代码

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let array1 = [Enum].all
        print("\(array1)")

        let array2 = [StringEnum].all
        print("\(array2)")
    }
}

enum Enum: EnumIterator  {
    case val1, val2, val3

    static func getItem(at index: Int) -> Enum? {
        switch index {
        case 0: return .val1
        case 1: return .val2
        case 2: return .val3
        default: return nil
        }
    }
}

enum StringEnum: String, EnumIterator  {
    case str1="str1", str2="str2", str3="str3"

    static func getItem(at index: Int) -> StringEnum? {
        switch index {
        case 0: return .str1
        case 1: return .str2
        case 2: return .str3
        default: return nil
        }
    }
}

Results

获取所有enum值作为数组


获取所有enum值作为数组


获取所有enum值作为数组

#9


0  

You Can Use

您可以使用

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

#1


8  

I found somewhere this code:

我在什么地方找到了这个密码:

protocol EnumCollection : Hashable {}


extension EnumCollection {

    static func cases() -> AnySequence<Self> {
        typealias S = Self
        return AnySequence { () -> AnyGenerator<S> in
            var raw = 0
            return AnyGenerator {
                let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory }
                guard current.hashValue == raw else { return nil }
                raw += 1
                return current
            }
        }
    }
}

Use:

使用:

enum YourEnum: EnumCollection { //code }

YourEnum.cases()

return list of cases from YourEnum

从YourEnum返回病例列表

#2


16  

For Swift 4.2 (Xcode 10) and later

There's a CaseIterable protocol:

有一个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)
}

For Swift < 4.2

No, you can't query an enum for what values it contains. See this article. You have to define an array that list all the values you have:

不,您不能查询枚举包含的值。看到这篇文章。你必须定义一个列有所有值的数组:

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

#3


9  

There's another way that at least is safe at compile time:

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

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

Notice that this works for any enum type (RawRepresentable or not) and also if you add a new case then you will get a compiler error which is good since will force you to have this up to date.

请注意,这适用于任何enum类型(RawRepresentable或not),而且如果您添加一个新案例,那么您将会得到一个编译器错误,这很好,因为它将迫使您更新此内容。

#4


3  

Swift 4.2 introduces a new protocol named CaseIterable

Swift 4.2引入了一种名为CaseIterable的新协议

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

that when you conforms to , you can get an array from the enum cases like this

当你遵守时,你可以从enum实例中获得一个数组,就像这样

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

#5


2  

For Swift 2

斯威夫特2

// Found http://*.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))
}

To use it:

使用它:

arrayEnum(MyEnumClass.self)

#6


1  

After inspiration from Sequence and hours of try n errors. I finally got this comfortable and beautiful Swift 4 way on Xcode 9.1:

从序列和数小时的尝试中获得灵感。我终于在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
    }
}

Usage:

用法:

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

Output:

输出:

Pending
On Hold
Done

#7


0  

If your enum is incremental and associated with numbers, you can use range of numbers that you map to enum values, like so:

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

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

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

This doesn't quite work with enums associated with strings or anything other than numbers, but it works great if that is the case!

这并不完全适用于与字符串或除数字之外的任何东西相关的枚举,但如果是这样的话,它将非常有效!

#8


0  

Details

Xcode 9.1, Swift 4

Xcode 9.1,斯威夫特4

Solution

protocol EnumIterator {
    static func getItem(at index: Int) -> Self?
}

extension Array where Element: EnumIterator {

    static var all: [Element] {
        var result = [Element]()
        var index = 0
        while true {
            if let item = Element.getItem(at: index) {
                result.append(item)
                index += 1
            } else {
                break
            }
        }
        return result
    }
}

Usage

enum

枚举

enum Enum: EnumIterator  {
    case val1, val2, val3

    static func getItem(at index: Int) -> Enum? {
        switch index {
        case 0: return .val1
        case 1: return .val2
        case 2: return .val3
        default: return nil
        }
    }
}

Array with all enum values

具有所有枚举值的数组

 let array = [Enum].all

Full sample

Do not forget to insert the solution code here

不要忘记在这里插入解决方案代码

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let array1 = [Enum].all
        print("\(array1)")

        let array2 = [StringEnum].all
        print("\(array2)")
    }
}

enum Enum: EnumIterator  {
    case val1, val2, val3

    static func getItem(at index: Int) -> Enum? {
        switch index {
        case 0: return .val1
        case 1: return .val2
        case 2: return .val3
        default: return nil
        }
    }
}

enum StringEnum: String, EnumIterator  {
    case str1="str1", str2="str2", str3="str3"

    static func getItem(at index: Int) -> StringEnum? {
        switch index {
        case 0: return .str1
        case 1: return .str2
        case 2: return .str3
        default: return nil
        }
    }
}

Results

获取所有enum值作为数组


获取所有enum值作为数组


获取所有enum值作为数组

#9


0  

You Can Use

您可以使用

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