Skip to content
Lesson 7 of 15

Step 1 of 5 · Reading · ~3 min

Learn

Control Flow

Loops

Swift's workhorse loop is for ... in. It does not count — it walks a sequence, and a range is just one kind of sequence.

for i in 1...3 {
    print(i)
}

//> 1
//> 2
//> 3

Two range operators, one off-by-one

OperatorName1 ... 5 / 1 ..< 5 produces
...closed range1 2 3 4 5
..<half-open range1 2 3 4
print(Array(1...5))
print(Array(1..<5))
print((1...5).count, (1..<5).count)

//> [1, 2, 3, 4, 5]
//> [1, 2, 3, 4]
//> 5 4

Use ..< when the upper bound is a count (for i in 0..<items.count) and ... when it is a value you want included (for i in 1...n). Picking the wrong one is the most common loop bug in any language, and Swift at least makes the choice visible in the syntax.

Walking things other than numbers

let names = ["ada", "grace", "alan"]

for name in names {
    print(name)
}

for (i, name) in names.enumerated() {
    print("\(i): \(name)")
}

//> ada
//> grace
//> alan
//> 0: ada
//> 1: grace
//> 2: alan

enumerated() is how you get an index without counting by hand. Reach for it instead of for i in 0..<names.count — you can never index out of bounds with it.

Strings iterate by Character, and stride covers the "every nth" case:

for c in "hi!" {
    print(c)
}
print(Array(stride(from: 0, to: 10, by: 3)))

//> h
//> i
//> !
//> [0, 3, 6, 9]

Filtering inside the loop header

A where clause skips iterations without an extra level of indentation:

var total = 0
for i in 1...5 where i % 2 == 1 {
    total += i
}
print(total)

//> 9

while and repeat-while

Use while when you do not know how many iterations there will be:

var n = 16
var halvings = 0
while n > 1 {
    n /= 2
    halvings += 1
}
print(halvings)

//> 4

repeat ... while is Swift's name for do ... while — the body runs before the condition is ever tested, so it always executes at least once:

var count = 3
repeat {
    count -= 1
} while count > 0
print(count)

//> 0

Getting out early

break leaves the loop entirely; continue skips to the next iteration.

var kept: [Int] = []
for i in 1...10 {
    if i % 2 == 0 { continue }
    if i > 7 { break }
    kept.append(i)
}
print(kept)

//> [1, 3, 5, 7]

continue fires on every even number, so i == 8 never reaches the break test — the loop ends at 9 instead. Guard order matters inside loops just as it does inside a switch.

Your exercise

Read a positive integer n and print the sum 1 + 2 + ... + n.

The mistake the grader catches is the half-open range. Writing for i in 1..<n stops at n - 1, so the first visible test with 5 prints 10 instead of 15, and the hidden test with 100 prints 4950 instead of 5050. You want 1...n. The other way to lose the test is to print inside the loop — accumulate into a running total declared with var before the loop and print once, after it.

Up nextFunctionsFunctions and Closures

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…