Swift Loops

Repeat work with for-in over ranges and collections, step through numbers with stride, use while and repeat-while, and control loops with break, continue and where.

Lesson 7 of 43Beginner17 min read

Loops let a program repeat work: show every message in a chat, add up the prices in a basket, count down a timer, retry a download until it succeeds. Swift's main loop is for-in, which visits each item in a sequence such as a range of numbers, an array or the characters of a string.

Swift describes sequences of numbers with ranges: 1...5 includes five, while 1..<5 stops before it. For counting in steps or backwards there's stride. And for repeating "until something happens", there are while and repeat-while loops.

In this lesson you'll loop over ranges, collections and strings, count in steps, filter with where, get positions with enumerated(), and control loops with break, continue and labels.

for-in and ranges

Swift
for i in 1...5 {
    print(i)            // 1, 2, 3, 4, 5
}
RangeValues
1...5 (closed)1, 2, 3, 4, 5
1..<5 (half-open)1, 2, 3, 4
(1...5).reversed()5, 4, 3, 2, 1
  • The loop constant (i) is created fresh each time and can't be changed inside the loop.
  • If you don't need it, write _: for _ in 1...3 { print("Hip hip!") }.
  • Half-open ranges are perfect for array positions: 0..<array.count.

Looping over collections

Swift
let fruits = ["apple", "pear", "plum"]
for fruit in fruits { print(fruit) }
for (index, fruit) in fruits.enumerated() {
    print("\(index + 1). \(fruit)")
}
for ch in "Swift" { print(ch) }

enumerated() gives pairs of position and item, unpacked into two names. Looping directly over a collection is safer than counting positions yourself, because you can't go past the end. Add where to skip items: for n in numbers where n > 0.

stride

stride counts in steps of any size, forwards or backwards:

Swift
for t in stride(from: 0, to: 30, by: 10) { }        // 0, 10, 20 (stops before 30)
for t in stride(from: 0, through: 30, by: 10) { }   // 0, 10, 20, 30
for t in stride(from: 10, through: 0, by: -5) { }   // 10, 5, 0

to: excludes the end and through: includes it, just like ..< and .... Stride also works with Doubles: stride(from: 0.0, to: 1.0, by: 0.25).

while, repeat-while, break and continue

A while loop checks its condition before each pass; repeat { } while condition checks after, so it always runs at least once.

  • break leaves the loop immediately.
  • continue skips the rest of this pass and moves to the next.
  • In nested loops, label the outer loop (outer: for ...) and use break outer to leave both.
Swift
var balance = 100.0
var years = 0
while balance < 200 {
    balance *= 1.05
    years += 1
}

zip, indices and forEach

Sometimes you need to walk through two arrays side by side. zip pairs them up, item by item, and stops at the end of the shorter one:

Swift
let names = ["Ada", "Grace", "Linus"]
let scores = [90, 85]
for (name, score) in zip(names, scores) {
    print("\(name): \(score)")
}
// Ada: 90
// Grace: 85   (Linus has no score, so he's skipped)

When you need positions, loop over indices rather than writing 0..<array.count. It gives exactly the valid positions, and it's an empty loop when the array is empty: for i in names.indices { print(i, names[i]) }.

You'll also see forEach, which runs a closure for each item: names.forEach { print($0) }. It looks similar to for-in, but it behaves differently in two ways:

for-inforEach
break and continueAllowedNot allowed
returnLeaves the whole functionSkips only the current item

Use for-in when you might stop early. forEach suits a short, single action at the end of a chain of operations.

Swift Loops Syntax

Loops

for i in 1...10 { }
for i in 0..<n { }
for item in array { }
for (i, item) in array.enumerated() { }
for n in numbers where n > 0 { }
for x in stride(from: 10, through: 0, by: -2) { }
while cond { }
repeat { } while cond
outer: for a in xs { for b in ys { break outer } }

Swift Loops Summary

  • for item in sequence loops over ranges, arrays, strings and more.
  • 1...5 includes 5; 1..<5 stops before it; _ ignores the loop value.
  • enumerated() gives position and item; where filters which items run.
  • stride(from:to:by:) excludes the end and stride(from:through:by:) includes it; negative steps count down.
  • while checks first, repeat-while runs at least once; break, continue and labels control loops.

Swift Loops Examples

Each example shows the code, the output it produces and what each part does.

Example 1

A times table and a countdown

Swift
let n = 7
for i in 1...5 {
    print("\(n) x \(i) = \(n * i)")
}

for s in stride(from: 10, through: 0, by: -5) {
    print(s, terminator: " ")
}
print("Liftoff!")
Output
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
10 5 0 Liftoff!
Line-by-line explanation
  1. Line 21...5 includes both ends.
  2. Line 6stride with a negative step counts down; through includes 0.
  3. Line 7terminator keeps the countdown on one line.
Example 2

Totals with enumerated and where

Swift
let prices = [2.50, 4.00, 1.25, 9.99]
var total = 0.0

for (i, price) in prices.enumerated() {
    print("Item \(i + 1): £\(price)")
    total += price
}
print("Total: £\(total)")

for price in prices where price < 2 {
    print("Bargain: £\(price)")
}
Output
Item 1: £2.5
Item 2: £4.0
Item 3: £1.25
Item 4: £9.99
Total: £17.740000000000002
Bargain: £1.25
Line-by-line explanation
  1. Line 4enumerated gives each position and price.
  2. Line 5Doubles print in their shortest form, so 2.50 shows as 2.5.
  3. Line 8Adding binary floating point numbers can leave a tiny error; format money for display, as the formatting lesson shows.
  4. Line 10where runs the loop body only for cheap items.
Example 3

while, repeat-while, break and continue

Swift
var savings = 1000.0
var years = 0
while savings < 1500 {
    savings *= 1.1
    years += 1
}
print("Years to reach 1500: \(years)")

var attempts = 0
repeat {
    attempts += 1
    print("Attempt \(attempts)")
} while attempts < 2

for n in 1...10 {
    if n % 2 == 0 { continue }
    if n > 7 { break }
    print(n, terminator: " ")
}
print()
Output
Years to reach 1500: 5
Attempt 1
Attempt 2
1 3 5 7 
Line-by-line explanation
  1. Lines 3 to 6Grow by 10% a year: 1100, 1210, 1331, 1464.1, then 1610.51 after 5 years.
  2. Lines 10 to 13repeat-while runs the body first, then checks the condition.
  3. Line 16continue skips even numbers.
  4. Line 17break stops the loop once n passes 7.

Common Swift Loops Mistakes

Off by one with ranges

Don't
let items = ["a", "b", "c"]
for i in 0...items.count { print(items[i]) }    // crash: index out of range
Do
for i in 0..<items.count { print(items[i]) }
// or simply: for item in items { print(item) }

Counting down with a range

Don't
for i in 5...1 { print(i) }      // crash: range requires lowerBound <= upperBound
Do
for i in (1...5).reversed() { print(i) }

A while loop that never ends

Don't
var tries = 0
while tries < 3 {
    print("Trying")              // tries never changes
}
Do
var tries = 0
while tries < 3 {
    print("Trying")
    tries += 1
}

Swift Loops in Real Projects

Loops in apps

Apps loop over lists of data to build screens, totals and summaries, though in SwiftUI the ForEach view does the looping for lists you display. Games loop every frame to update positions, and data-processing code loops over files and records. In practice, Swift developers also use collection methods like map, filter and reduce, covered in the closures lesson, to replace many hand-written loops.

Swift Loops FAQ

What is the difference between ... and ..< in Swift?

1...5 is a closed range that includes both ends, giving 1 to 5. 1..<5 is half-open and stops before the upper bound, giving 1 to 4. Use ..< with counts and array positions, so 0..<items.count covers every valid index.

How do I loop backwards in Swift?

Reverse a range with for i in (1...5).reversed(), or use stride(from: 5, through: 1, by: -1). A range like 5...1 isn't allowed: the program crashes because the lower bound is greater than the upper bound.

How do I get the index in a for-in loop?

Use enumerated(): for (index, item) in items.enumerated() gives each position, starting at 0, along with the item. If you only need positions, for i in items.indices is clearer.

Does Swift have a C-style for loop?

No. for (i = 0; i < 10; i++) was removed in Swift 3. Use for i in 0..<10 for counting, stride(from:to:by:) for other step sizes, and a while loop when the stopping rule is more complicated.

How do I break out of nested loops in Swift?

Put a label before the outer loop, such as outer: for row in grid, then write break outer inside the inner loop. A plain break would only leave the inner loop. continue outer works the same way to skip to the next outer pass.

Swift Loops Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the loop so it runs for 0, 1, 2 and 3.

for i in 04 { print(i) }
Predict the outputeasy

How many times does for _ in 1...3 { } run?

Predict the outputmedium

What does this print?

for x in stride(from: 1, to: 10, by: 3) { print(x, terminator: " ") }
Multiple choicemedium

Which loop always runs its body at least once?

Predict the outputhard

What does this print?

var total = 0
for n in 1...6 where n != 4 {
    total += n
}
print(total)

Swift Loops Quiz

5 questions to check what you learned.

  1. Does the range 1...3 include 3?

    • Yes
    • No
    • Only in while loops
    • Only with stride
  2. What does enumerated() give in a for-in loop?

    • Only positions
    • A sorted copy
    • Pairs of position and item
    • The count
  3. What does continue do?

    • Ends the loop
    • Skips to the next pass of the loop
    • Restarts from the beginning
    • Pauses the app
  4. How do you count 10, 8, 6 ... 0?

    • for i in stride(from: 10, through: 0, by: -2)
    • for i in 10...0
    • for i in 0...10 by 2
    • for i in (0..<10).step(2)
  5. What happens with for i in 5...1?

    • It counts down
    • It does nothing
    • It compiles but warns
    • The program crashes, because a range's lower bound can't be above its upper bound