In This Article
In the previous chapter, you learned if statements and while loops. Now it's time for the two most powerful control flow tools in Swift: the for loop (for repeating work a known number of times) and the switch statement (for making decisions with pattern matching). These are the tools you'll reach for most often in real code.
Ranges: Sequences of Numbers
Before you can use for loops, you need to know about ranges — Swift's way of representing a sequence of consecutive integers.
The three-dot operator (...) creates a closed range that includes both the start and end values. The two-dot-less-than operator (..<) creates a half-open range that stops one before the end.
Half-open ranges are especially common in programming because arrays use zero-based indexing. A 5-element array has indices 0 through 4, which is exactly 0..<5.
For Loops: Iterating a Known Number of Times
The for-in loop is the most common loop in Swift. It iterates over a range (or any sequence) and runs the body once for each value:
On each iteration, i takes the next value in the range. The constant i is scoped to the loop — it doesn't exist outside it.
When you don't need the loop variable
Sometimes you just want to repeat something a fixed number of times without caring which iteration you're on. Use the underscore:
The underscore tells Swift (and anyone reading your code) that you intentionally aren't using the loop counter.
Filtering With where
You can add a where clause to a for loop to only execute the body when a condition is met:
The loop still iterates through all values 1 to 10, but it only runs the body when i is odd. This is cleaner than putting an if statement inside the loop.
Continue and Labeled Statements
The continue statement skips the rest of the current iteration and moves to the next one. It's like break, but instead of exiting the loop entirely, it just skips ahead:
Labeled statements for nested loops
When you have nested loops, break and continue act on the innermost loop by default. To control an outer loop, give it a label:
By writing continue rowLoop, you skip the rest of the inner loop AND the rest of the current outer iteration, jumping directly to the next row.
Switch Statements
The switch statement is Swift's most powerful decision-making tool. It inspects a value and runs different code depending on what it matches:
Key rules for Swift switch statements:
- Exhaustive — every switch must handle all possible values. Use
defaultas a catch-all. - No fallthrough — unlike C or Java, Swift doesn't fall through to the next case. Each case is isolated.
- Never empty — if a case should do nothing, write
break. - Multiple values — a single case can match multiple values separated by commas.
Switch With Ranges
You can use ranges in switch cases, which makes them incredibly clean for categorizing numeric values:
Compare this to the if/else if chain from the previous chapter — the switch version is more concise, more readable, and handles invalid input (negative numbers) correctly through the default case.
Pattern Matching With let-where
Here's where Swift's switch really shines. You can use let to bind values and where to add conditions:
The let x binds the value to a name, and where x % 2 == 0 adds a condition. The case only matches if the condition is true. This is called pattern matching, and it's one of Swift's most distinctive features.
If you don't need the binding (since you already have number), use an underscore:
Partial Matching With Tuples
Switch statements become extremely powerful with tuples. You can match on some elements while ignoring others:
The underscore means "match anything." The last case binds all three values and serves as the default — since it matches everything, no explicit default is needed.
You can combine binding with conditions for even more powerful matching:
Use if for simple true/false decisions. Use switch when you're checking a value against multiple possible matches, especially with ranges, tuples, or pattern matching. Switch statements are also preferred when you need to be exhaustive — the compiler ensures you handle every case.
Exercises
Try These in Your Playground
- Use a
forloop to print the squares of numbers 1 through 10 (1, 4, 9, 16...). - Write a
forloop with awhereclause that sums only the even numbers from 1 to 100. - Write a
switchstatement that takes an age (Int) and prints the life stage: 0-2 Infant, 3-12 Child, 13-19 Teenager, 20-39 Adult, 40-60 Middle-aged, 61+ Elderly. - Write a
switchon a tuple(name: String, age: Int)that usesletbinding to print "Name is a life stage". - Print a countdown from 10 to 0 using a
forloop and a closed range. (Hint: calculate10 - i.) - Challenge: Using nested
forloops, print a table showing how many ways you can roll each sum (2 through 12) with two six-sided dice.
Key Points
What You Learned
- Closed ranges (
0...5) include both endpoints; half-open ranges (0..<5) exclude the end for i in rangeiterates through each value, running the body once per value- Use
_instead of a loop variable when you don't need the counter - The
whereclause filters which iterations run the loop body continueskips to the next iteration;breakexits the loop entirely- Labeled statements let
continueandbreaktarget outer loops in nested structures switchstatements must be exhaustive — they handle every possible value- Cases can match single values, multiple values (comma-separated), or ranges
- Pattern matching with
let-wherelets you bind values and add conditions to cases - Tuple partial matching uses
_to ignore specific elements - Swift switch cases don't fall through — only the first matching case executes
In the next chapter, we'll explore Functions — how to organize your code into reusable blocks, pass data in and get results back, and design clean APIs.
Watch the video lessons
Our Swift Fundamentals course covers for loops, switch, pattern matching, and real challenges in 96 video lessons.
Watch Swift Videos