Search code examples
swiftstringenumsenumerate

How to enumerate an enum with String type?


enum Suit: String {
    case spades = "♠"
    case hearts = "♥"
    case diamonds = "♦"
    case clubs = "♣"
}

For example, how can I do something like:

for suit in Suit {
    // do something with suit
    print(suit.rawValue)
}

Resulting example:

♠
♥
♦
♣

Solution

  • Swift 4.2+

    Starting with Swift 4.2 (with Xcode 10), just add protocol conformance to CaseIterable to benefit from allCases. To add this protocol conformance, you simply need to write somewhere:

    extension Suit: CaseIterable {}
    

    If the enum is your own, you may specify the conformance directly in the declaration:

    enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }
    

    Then the following code will print all possible values:

    Suit.allCases.forEach {
        print($0.rawValue)
    }
    

    Compatibility with earlier Swift versions (3.x and 4.x)

    If you need to support Swift 3.x or 4.0, you may mimic the Swift 4.2 implementation by adding the following code:

    #if !swift(>=4.2)
    public protocol CaseIterable {
        associatedtype AllCases: Collection where AllCases.Element == Self
        static var allCases: AllCases { get }
    }
    extension CaseIterable where Self: Hashable {
        static var allCases: [Self] {
            return [Self](AnySequence { () -> AnyIterator<Self> in
                var raw = 0
                var first: Self?
                return AnyIterator {
                    let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
                    if raw == 0 {
                        first = current
                    } else if current == first {
                        return nil
                    }
                    raw += 1
                    return current
                }
            })
        }
    }
    #endif