154

I have the following 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"]).

I added this method to the 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 '(() -> _)'

Is there is an easier, better or more elegant way to do this?

4
  • 2
    you can create array like let array : [EstimateItemStatus] = [.Pending, .Onhold, .Done] Commented Oct 5, 2015 at 15:41
  • 2
    @KristijanDelivuk I want to add this functionality to the enum itself. So I don't have to go and add it everywhere in other places of the codebases if I ever add another value to the enum. Commented Oct 5, 2015 at 15:47
  • Possible duplicate of How to enumerate an enum with String type? Commented May 1, 2017 at 0:19
  • I have an answer you can refer to here stackoverflow.com/a/48960126/5372480 Commented May 16, 2018 at 20:01

13 Answers 13

247

For Swift 4.2 (Xcode 10) and later

There's a CaseIterable protocol:

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. Also check out Frank Valbuena's solution in "How to get all enum values as an array".

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)
}
Sign up to request clarification or add additional context in comments.

4 Comments

See this answer: stackoverflow.com/a/28341290/8047 including the Swift 3 code.
Upvoting for the allValues part, but not sure what to feel about an enum being type String but initialized with Int.
The first link is broken but appears to be at exceptionshub.com/… now.
If I want to delete "OnHold" by checking a condition, what would be the best approach?
106

Swift 5

Add CaseIterable protocol to enum:

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

Usage:

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

1 Comment

+1. Should be the accepted answer post Swift 5. You can also do static let values: [String] ... inside the enum to make it nicer.
52

Swift 4.2 introduces a new protocol named 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

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

Comments

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

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

["Pending", "OnHold", "Done"]

1 Comment

With the shorthand expression, this looks pretty cool though..
17

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.

2 Comments

Unorthodox, but it works and it warns you if you modify the enum cases. Clever solution!
I've never seen like this way. It looks very interesting. But I don't understand some of your codes. How can you put MyEnum.case1 to switch condition? and how did you avoid the error Switch condition evaluates to a constant?
14

To get a list for functional purposes, use the expression EnumName.allCases which returns an array e.g.

EnumName.allCases.map{$0.rawValue} 

will give you a list of Strings given that EnumName: String, CaseIterable

Note: use allCases instead of AllCases().

Comments

12

I found somewhere this code:

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

Use:

enum YourEnum: EnumCollection { //code }

YourEnum.cases()

return list of cases from YourEnum

3 Comments

Seems like a great solution but has quite a few compile errors on Swift 4.
The "somewhere" may be: theswiftdev.com/2017/10/12/swift-enum-all-values (among others?). The blogger credits CoreKit.
This breaks in XCode 10 (regardless of Swift-version) as the hashValue of an enum no longer incremental but random, breaking the mechanism. The new way to do this is to upgrade to Swift 4.2 and use CaseIterable
3

Update for Swift 5

Easiest solution I've found is to use .allCases on an enum that extends 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 on any CaseIterable enum will return a Collection of that element.

var myEnumArray = EstimateItemStatus.allCases

more info about CaseIterable

2 Comments

There is no need to implement description(). Just equate each case to the string eg case OnHold = "On Hold" and that becomes the raw value for each.
@pnizzle I know, it's there because it was in the original question.
2

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

2 Comments

Nice! After upgrading from Swift 3.2 to 4.1 this was a solution that I used. We originally had AnyItertor<Self> declarations. Your solution was much cleaner and easier to read. thanks!
One code flaw here though. It misses the first item in the case. Change var index = 1 to var index = 0
1

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

To use it:

arrayEnum(MyEnumClass.self)

1 Comment

Why would the elements' hashValue be 0..n?
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:

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

Comments

1

Extension on an enum to create allValues.

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

1 Comment

While this code may provide a solution to OP's problem, it is highly recommended that you provide additional context regarding why and/or how this code answers the question. Code only answers typically become useless in the long-run because future viewers experiencing similar problems cannot understand the reasoning behind the solution.
0

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

// 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!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.