Control Flow in Swift
Master conditionals, loops, and pattern-matching control flow in Swift with if/else, switch, for-in, while, guard, and Docker-ready examples
Control flow is how a program decides what to do and how many times to do it. Swift offers a familiar set of constructs — if/else, for-in, while — but pairs them with features that reflect its safety-first, expressive design. The switch statement is far more powerful than the C-style switch most developers know, supporting full pattern matching, value binding, and range checks. And the guard statement provides an idiomatic way to handle the “unhappy path” early and keep the main logic flat and readable.
As a multi-paradigm language, Swift lets you write imperative loops when they’re clearest, but also encourages a more functional style where switch matches on shape and value rather than chaining conditionals. A standout safety feature is that switch statements must be exhaustive — the compiler forces you to handle every possible case, eliminating a whole class of “I forgot that branch” bugs.
In this tutorial you’ll learn Swift’s conditionals (if/else if/else and the ternary operator), its pattern-matching switch, the various loop forms (for-in, while, repeat-while), loop control with break and continue, and the early-exit guard statement. Every example is a complete, runnable script.
Conditionals: if, else if, and the Ternary Operator
The if statement runs a block when its condition is true. Unlike C, Swift does not require parentheses around the condition, but braces are always mandatory — even for a single statement.
Create a file named conditionals.swift:
| |
Note that Swift conditions must evaluate to a Bool. You cannot write if temperature and expect a non-zero number to be “truthy” — this strictness prevents a common source of bugs.
The switch Statement and Pattern Matching
Swift’s switch is one of its most powerful features. Cases don’t “fall through” by default (no break needed), each case can match ranges or tuples, and the whole statement must be exhaustive.
Create a file named switch_demo.swift:
| |
Here the case (let x, 0) syntax binds the matched value to a constant you can use in the body, and where adds an extra condition. Because the cases above cover every possibility (with default), the switch compiles.
For-In Loops
The for-in loop iterates over any sequence: ranges, arrays, dictionaries, strings, and more. Swift’s range operators make numeric loops concise.
Create a file named for_loops.swift:
| |
The underscore _ is Swift’s “I don’t care about this value” placeholder — useful when you want to repeat an action a fixed number of times.
While and Repeat-While Loops
When you don’t know the iteration count in advance, use a while loop (checks the condition before each pass) or a repeat-while loop (checks after, so the body always runs at least once). Swift’s repeat-while is the equivalent of C’s do-while.
Create a file named while_loops.swift:
| |
Loop Control: break and continue
break exits a loop immediately; continue skips to the next iteration. Swift also supports labeled statements, which let you break out of an outer loop from within a nested one.
Create a file named loop_control.swift:
| |
The label outer: names the outer loop, so break outer terminates both loops at once — much cleaner than juggling a flag variable.
Early Exit with guard
The guard statement is Swift’s idiomatic tool for early returns. It runs a block (which must exit the current scope) when its condition is false, letting you handle preconditions up front and keep the rest of the function unindented. Crucially, values bound with guard let remain in scope after the guard.
Create a file named guard_demo.swift:
| |
Compare this to nesting everything inside if let blocks — guard keeps the “happy path” at the top indentation level, which is why Swift developers reach for it constantly.
Running with Docker
You can run every example above without installing Swift locally by using the official image.
| |
Expected Output
Running conditionals.swift:
Mild
Result: Pass
Ready to go
Running switch_demo.swift:
Client error
On the x-axis at 3
e is a vowel
Running for_loops.swift:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
---
Index: 0
Index: 1
Index: 2
---
Language: Swift
Language: Rust
Language: Go
---
0: Swift
1: Rust
2: Go
---
Even: 0
Even: 2
Even: 4
Even: 6
Even: 8
---
Total: 30
Running while_loops.swift:
T-minus 3
T-minus 2
T-minus 1
Liftoff!
---
Attempt 1
Attempt 2
Attempt 3
Done after 3 attempts
Running loop_control.swift:
Even numbers:
2
4
6
8
10
Stopping early:
1
2
3
4
Searching grid:
Checking (1, 1)
Checking (1, 2)
Checking (1, 3)
Checking (2, 1)
Found target at (2, 2)
Running guard_demo.swift:
25: adult
15: minor
Age cannot be negative
'hello' is not a valid number
Key Concepts
- Conditions must be
Bool— Swift has no “truthy” values, soif 1is a compile error; this strictness prevents subtle bugs. switchis exhaustive and pattern-matching — cases can match ranges, tuples, and bind values withlet, refined bywhereclauses, and the compiler forces you to handle every case.- No implicit fallthrough — Swift
switchcases don’t fall through, so you never needbreakto stop one case bleeding into the next (use the explicitfallthroughkeyword if you actually want it). - Rich range operators —
1...5(closed) and0..<3(half-open), plusstride(from:to:by:), make numericfor-inloops concise and clear. repeat-whileruns at least once — it’s Swift’sdo-while, checking the condition after the body executes.- Labeled loops — naming a loop (e.g.
outer:) letsbreak/continuetarget an outer loop from inside a nested one, avoiding flag variables. guardenforces early exit — itselseblock must leave the current scope, and bindings fromguard letstay in scope afterward, keeping the main logic flat and readable.
Comments
Loading comments...
Leave a Comment