Advanced Control Flow: For Loops, Switch & Pattern Matching

Swift Chapter 6 of the Ultimate Swift Series 28 min read April 10, 2026 Beginner

In This Article

  1. Ranges: Sequences of Numbers
  2. For Loops: Iterating a Known Number of Times
  3. Filtering With where
  4. Continue and Labeled Statements
  5. Switch Statements
  6. Switch With Ranges
  7. Pattern Matching With let-where
  8. Partial Matching With Tuples
  9. Exercises
  10. Key Points

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.

// Closed range: includes both endpoints (0, 1, 2, 3, 4, 5) let closed = 0...5 // Half-open range: includes start, excludes end (0, 1, 2, 3, 4) let halfOpen = 0..<5

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:

let count = 10 var sum = 0 for i in 1...count { sum += i } print(sum) // 55 (1 + 2 + 3 + ... + 10)

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:

var result = 1 for _ in 0..<5 { result *= 2 } print(result) // 32 (2^5)

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:

var oddSum = 0 for i in 1...10 where i % 2 == 1 { oddSum += i } print(oddSum) // 25 (1 + 3 + 5 + 7 + 9)

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:

var sum = 0 for row in 0..<8 { if row % 2 == 0 { continue // Skip even rows } for col in 0..<8 { sum += row * col } } // sum = 448 (only odd rows contribute)

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:

var sum = 0 rowLoop: for row in 0..<8 { columnLoop: for col in 0..<8 { if row == col { continue rowLoop // Skip to next ROW, not just next column } sum += row * col } }

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:

let animal = "Dog" switch animal { case "Cat", "Dog": print("House pet") case "Tiger", "Lion": print("Wild cat") default: print("Unknown animal") } // Prints: "House pet"

Key rules for Swift switch statements:

Switch With Ranges

You can use ranges in switch cases, which makes them incredibly clean for categorizing numeric values:

let hour = 14 var period: String switch hour { case 0...5: period = "Early morning" case 6...11: period = "Morning" case 12...16: period = "Afternoon" case 17...19: period = "Evening" case 20..<24: period = "Late evening" default: period = "Invalid hour" } print(period) // "Afternoon"

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:

let number = 42 switch number { case let x where x % 2 == 0: print("\(x) is even") default: print("\(number) is odd") } // Prints: "42 is even"

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:

switch number { case _ where number % 2 == 0: print("Even") default: print("Odd") }

Partial Matching With Tuples

Switch statements become extremely powerful with tuples. You can match on some elements while ignoring others:

let point = (x: 3, y: 0, z: 0) switch point { case (0, 0, 0): print("At the origin") case (_, 0, 0): print("On the x-axis") case (0, _, 0): print("On the y-axis") case (0, 0, _): print("On the z-axis") case let (x, y, z): print("At (\(x), \(y), \(z))") } // Prints: "On the x-axis"

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:

let point2D = (x: 4, y: 4) switch point2D { case let (x, y) where y == x: print("On the line y = x") case let (x, y) where y == x * x: print("On the curve y = x\u{00B2}") default: break } // Prints: "On the line y = x"
Switch vs. if — when to use which

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

  1. Use a for loop to print the squares of numbers 1 through 10 (1, 4, 9, 16...).
  2. Write a for loop with a where clause that sums only the even numbers from 1 to 100.
  3. Write a switch statement 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.
  4. Write a switch on a tuple (name: String, age: Int) that uses let binding to print "Name is a life stage".
  5. Print a countdown from 10 to 0 using a for loop and a closed range. (Hint: calculate 10 - i.)
  6. Challenge: Using nested for loops, 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

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