For the technical joy of it: another alternative would be to define a sequence which cycles over the elements of the array.
Given an immutable array:
class Foo {
private let array: [String]
private lazy var cyclingSequenceOverArray:
UnfoldSequence<String, Int> = sequence(state: -1) {
(state: inout Int) -> String? in
guard !self.array.isEmpty else { return nil }
return self.array[(state = (state + 1) % self.array.count, state).1]
}
init(_ array: [String]) {
self.array = array
}
func printNext() {
if let next = cyclingSequenceOverArray.next() {
print(next)
}
}
}
let foo = Foo(["a", "b", "c", "d"])
foo.printNext() // a
foo.printNext() // b
foo.printNext() // c
foo.printNext() // d
foo.printNext() // a
foo.printNext() // b
In the case where you let the array be mutable (var) and it ever becomes empty: a call to the next() method (as implemented above) of the sequence will terminate the sequence. I.e., even if the array were to be re-filled, subsequent calls to next() would still yield nil. In this case, you could let the sequence be infinite (never-terminating), simply returning a default value in case the array is nil:
class Foo {
var array: [String]
private lazy var cyclingSequenceOverArray:
UnfoldSequence<String, Int> = sequence(state: -1) {
(state: inout Int) -> String in
guard !self.array.isEmpty else { return (state = -1, "Empty!").1 }
return self.array[(state = (state + 1) % self.array.count, state).1]
}
init(_ array: [String]) {
self.array = array
}
func printNext() {
if let next = cyclingSequenceOverArray.next() {
print(next)
}
}
}
Example usage:
let foo = Foo(["a", "b", "c", "d"])
foo.printNext() // a
foo.printNext() // b
foo.printNext() // c
foo.array = []
foo.printNext() // Empty!
foo.printNext() // Empty!
foo.array = ["a", "b", "c", "d"]
foo.printNext() // a
foo.printNext() // b
foo.array[2] = "C"
foo.printNext() // C
foo.array = ["1", "2", "3"]
foo.printNext() // 1