A for loop is used for iterating over a sequence. The Swift for loop is schematized in followin example.
for variable in sequence { statements }
In the for...in
construct, the variable is implicitly declared with let
on each iteration; it is thus immutable by default. If you need to assign to the variable within the block, write for var
. The variable is also local to the block. On each iteration, a successive element of the sequence is used to initialize the variable, which is then in scope inside the block.
A common use of for loops is to iterate through successive numbers. This is easy in Swift, because you can readily create a sequence of numbers on the fly - a Range
:
for i in 1...5 { print(i) // 1, 2, 3, 4, 5 }
A for...in
construct can take a where
clause, allowing you to skip some values of the sequence:
for i in 0...10 where i % 2 == 0 { print(i) // 0, 2, 4, 6, 8, 10 }
Like if case
and while case
, there’s also for case
, permitting a switch case pattern to be used a for loop. The tag is each successive value of the sequence, so no assignment operator is used. To illustrate, let’s start with an array of MyError
enums:
let arr : [MyError] = [ .message("ouch"), .message("yipes"), .number(10), .number(-1), .fatal ]
Here we cycle through the whole array, extracting only the .number
associated values:
for case let .number(i) in arr { print(i) // 10, -1 }
Another common use of for case is to cast down conditionally, picking out only those members of the sequence that can be cast down safely. For example, let’s say I want to hide all subviews that happen to be buttons:
for case let b as UIButton in self.boardView.subviews { b.isHidden = true }
A sequence also has instance methods, such as map(_:)
, filter(_:)
, and reversed
; you can apply these to hone the sequence through which we will cycle. In this example, I count backward by even numbers:
let range = (0...10).reversed().filter{$0 % 2 == 0} for i in range { print(i) // 10, 8, 6, 4, 2, 0 }
Yet another approach is to generate the sequence by calling either stride(from:through:by)
or stride(from:to:by:)
. These are global functions applicable to adopters of the Strideable
protocol, such as numeric types and anything else that can be incremented and decremented. Which form you use depends on whether you want the sequence to include the final value. The by:
argument can be negative:
for i in stride(from: 10, through: 0, by: -2) { print(i) // 10, 8, 6, 4, 2, 0 }
For maximum flexibility, you can use the global sequence
function to generate your sequence by rule. It takes two parameters - an initial value, and a generation function that returns the next value based on what has gone before. In theory, the sequence generated by the sequence
function can be infinite in length - though this is not a problem, because the resulting sequence is "lazy" meaning that an element isn’t generated until you ask for it. In reality, you’ll use one of two techniques to limit the result. The generation function can limit the sequence by returning nil to signal that the end has been reached:
let seq = sequence(first:1) {$0 >= 10 ? nil : $0 + 1} for i in seq { print(i) // 1,2,3,4,5,6,7,8,9,10 }
Alternatively you can request just a piece of the infinite sequence - for example, by cycling through the sequence for a while and then stopping, or by taking a finite prefix
:
let seq = sequence(first:1) {$0 + 1} for i in seq.prefix(5) { print(i) // 1,2,3,4,5 }