Getting All Cases Of An Enum

I think my favourite addition to Swift 4.2 might be having the compiler automatically generate an allCases collection for enums.

How Many Cases In My Enum?

It is often useful to know how many cases an enum has or to be able to iterate over all possible cases. Before Swift 4.2 you either needed to use a meta-programming tool like Sourcery or manually maintain the collection:

enum Direction {
  case left
  case right
}

extension Direction {
  static let allItems: [Direction] = [.left, .right]
}

Direction.allItems.count
// 2
Direction.allItems.forEach { print($0) }
// left
// right

Doing it yourself is a pain and fails to work as expected when I add extra cases to the enum and forget about updating my implementation of allItems.

enum Direction {
  case left
  case right
  case up
  case down
}

Direction.allItems.count
// 2 ???

CaseIterable Protocol

Swift 4.2 brings us the CaseIterable protocol. This follows the pattern of Equatable, Comparable and Hashable by having the compiler automatically synthesize the implementation.

All you need to do is declare that your enum conforms to the protocol:

enum Direction: CaseIterable {
  case left
  case right
  case up
  case down
}

The compiler then provides you an allCases that is a collection of all cases of the enum:

Direction.allCases.count
// 4
Direction.allCases.forEach { print($0) }
// left right up down.

Notes:

  • The order of the collection follows the order of the enum declaration.

  • The compiler will not automatically synthesize an implementation for an enum with associated values since it could have an unlimited number of cases.

  • The documentation still states that you have to declare conformance in the enum’s original declaration. That is no longer true in Swift 4.2 you can declare conformance in an extension as long as you are in the same file:

    enum Direction { ... }
    extension Direction: CaseIterable {}
    
  • You can implement the CaseIterable protocol for yourself (see the post by Ole Begemann for an example). The disadvantage is that you are then back to maintaining the implementation and keeping it up to date if someone adds a new case to the enum.

Further Reading