Orestis Papadopoulos

Orestis Papadopoulos

Software, Sound, Swift

CaseSequencable: Put your enums in order

Enums are often used to model states. If we want to move to the next state (in order of declaration) we have to do the switch dance:

enum MyState {
  case sleeping
  case working
  case chilling
}

var myState: MyState = .sleeping

func nextState() {
	switch myState {
    case sleeping:
    ....
  }
}

By conforming an enum toCaseIterable type, we can access a collection of all of the type’s cases by using the type’s allCases property. The allCases property is compiler synthesized (for enums that don’t have associated values) and provides the cases in order of their declaration.

We can implement a simple protocol named CaseSequencable which inherits from the CaseIterable protocol:

protocol CaseSequencable: CaseIterable, Equatable {
    var nextCase: Self { get }
}

extension CaseSequencable {
    var nextCase: Self {
        // allCases is compiler synthesized (for enums without associated values)
        // there is no possible way for self to not exist in allCases
        // if you manually conform to CaseIterable it will crash :D
        let selfIndex = Self.allCases.firstIndex(of:self)!

        let nextIndex = Self.allCases.index(after: selfIndex)
        if nextIndex == Self.allCases.endIndex {
            return Self.allCases[Self.allCases.startIndex]
        } else {
            return Self.allCases[nextIndex]
        }
    }
}

And use it in the following way:

enum MyState: CaseSequencable {
  case sleeping
  case working
  case chilling
}

var myState: MyState = .sleeping

myState // .sleeping
myState.next // .working
myState.next.next // .chilling
myState.next.next.next // .sleeping (loops back to the first case)

Feel free to contact me or tweet to me on Twitter for tips, feedback, opinions.

Thank you for reading!