How to get next case of enum(i.e. write a circulating method) in Swift 4.2

Some problems with your approach are:

  • The Collection protocol does not define a last property.
  • In order to compare the elements with == they have to be Equatable.
  • Collection indices are not necessarily integers, they must be incremented with index(after:).

This seems to be a working solution (tested with Xcode 10.0 beta 2):

extension CaseIterable where Self: Equatable {
    func next() -> Self {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let next = all.index(after: idx)
        return all[next == all.endIndex ? all.startIndex : next]
    }
}

Example:

enum Direction: CaseIterable {
    case east, south, west, north
}

print(Direction.east.next()) // south
print(Direction.north.next()) // east

Remarks:

  • Only enumerations without associated values are CaseIterable, and those are also Equatable (but the compiler does not figure out that by itself). Therefore Self: Equatable is not a real restriction.
  • Self.allCases can be used in Swift 4.2 to access the type property from an instance method.
  • The forced unwrapping is safe because we know that the value is an element of allCases.
  • Your enum Direction: CaseIterable compiles because the concrete enum Direction type is Equatable, and its Direction.allCases is an Array – which has integer indices and a last property.

If someone is interested into both previous and next cases, here's an upgrade of the previous answer:

extension CaseIterable where Self: Equatable, AllCases: BidirectionalCollection {
    func previous() -> Self {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let previous = all.index(before: idx)
        return all[previous < all.startIndex ? all.index(before: all.endIndex) : previous]
    }

    func next() -> Self {
        let all = Self.allCases
        let idx = all.index(of: self)!
        let next = all.index(after: idx)
        return all[next == all.endIndex ? all.startIndex : next]
    }
}

Tags:

Enums

Swift