Swift 4.2 introduces a new CaseIterable
protocol that automatically generates an array property of all cases in an enum.
Now I want to implement a default m
Some problems with your approach are:
Collection
protocol does not define a last
property.==
they have to be Equatable
.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:
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.allCases
.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]
}
}