The for-in loop
A for loop repeats a block of code once for each item of a collection, such as an array. Swift's version is called for-in:
let fruits = ["banana", "orange", "pear", "kiwi"]
for fruit in fruits {
print("I eat \(fruit)")
}
I eat banana
I eat orange
I eat pear
I eat kiwi
The pieces of the loop are:
forstarts the loop.fruitis the loop variable. On each pass it holds the next item of the array.inseparates the loop variable from the collection.fruitsis the collection to go through.- The braces hold the body, the code that runs once per item.
You choose the name of the loop variable. A singular name for a plural array, like fruit for fruits, keeps the code easy to read.
The loop variable is a constant
You don't write let or var for the loop variable. Swift creates a new constant for each pass, so you can read it but not change it:
for friend in friends {
friend = "x"
}
error: cannot assign to value: 'friend' is a 'let' constant
The loop variable also exists only inside the braces. Using fruit after the loop is a compile error, cannot find 'fruit' in scope.
Building a result
A loop usually collects something. Declare a var before the loop, then update it in the body:
var total = 0
for n in [3, 4, 5] {
total += n
}
print(total)
12
Indexes, ranges and empty arrays
When you also need the position of each item, use enumerated(), which pairs each item with its index starting at 0. To loop a fixed number of times, loop over a range such as 0..<3 (3 excluded) or 1...3 (3 included):
for (i, fruit) in fruits.enumerated() {
print(i, fruit)
}
for i in 0..<fruits.count {
print(fruits[i])
}
0 banana
1 orange
2 pear
3 kiwi
banana
orange
pear
kiwi
If the array is empty, the body never runs and the loop finishes without an error. Using 0...fruits.count instead of 0..<fruits.count would be an off-by-one mistake: it reaches index 4 and the program crashes with an index out of range error.
Counting loops and walking backwards
When the loop variable isn't needed, write _ in its place so the body just repeats. To visit the indexes from last to first, reverse the array's indices:
for _ in 1...2 {
print("hi")
}
for i in fruits.indices.reversed() {
print(i)
}
hi
hi
3
2
1
0
The exercise
The starter code has an array friends. The task has two steps:
- Write a
for-inloop with the loop variablefriendoverfriends. - Inside the body, print
"Hey, \(friend)!". The\(...)inserts the current friend into the text.
let friends = ["Andy", "Mary", "John"]
for friend in friends {
print("Hey, \(friend)!")
}
Hey, Andy!
Hey, Mary!
Hey, John!
The body runs three times, once per friend, and adding a fourth friend to the array needs no other change.
Common mistakes
- Printing outside the braces. A statement after the closing brace runs once, after the loop.
- Misspelling the loop variable. The name in the body must match the name after
for, or the compiler reports that it cannot find the name in scope. - Changing the array while looping. The loop goes over the array as it was at the start, so appending inside the loop does not make it longer.
The same loop works on other collections too. A string gives its characters one at a time, and a range gives its numbers.
Key takeaways
for item in collection { ... }runs the body once per item.- The loop variable is a new constant on each pass and is visible only inside the loop.
- Use
enumerated()for indexes and0..<nfor counting loops.
