- August 28, 2025
- Mins Read
Control flow is about choosing paths (branches), repeating work (loops), and bailing out early (early exits). Swift emphasizes clarity and safety: booleans must be explicit, conditions can bind values, and many features (like switch patterns or guard) help you express intent succinctly.
Use for-in to iterate over sequences (arrays, ranges, dictionaries, sets, strings, async sequences).
let scores = [10, 15, 8]
for score in scores {
print(score)
}
for i in 0..<scores.count { // half-open range
print("Index \(i): \(scores[i])")
}
let capitals = ["UK": "London", "FR": "Paris"]
for (country, city) in capitals {
print("\(country): \(city)")
}
Key points:
Sequence.for _ in ignores the loop variable.for-in over C-style for (which Swift removed).for try await lets you iterate over an AsyncSequence.Swift offers while and repeat { ... } while. Use them when you don’t know the exact iteration count beforehand.
var x = 3
while x > 0 {
x -= 1
}
var input: String
repeat {
input = readLine() ?? ""
} while input.isEmpty
while checks the condition before each iteration.repeat-while runs the body once, then checks.if, else if, else)Classic branching:
let temperature = 28
if temperature > 30 {
print("Hot")
} else if temperature > 15 {
print("Mild")
} else {
print("Cold")
}
Swift requires a Boolean in if—no implicit integer-to-bool conversions. You can also bind optionals:
if let first = scores.first, first > 10 {
print("First score is big")
}
Or use guard for early exits (see §7).
Ternary operator (condition ? a : b) is available but keep it readable.
switchswitch in Swift is powerful: exhaustive by default, supports complex patterns, value binding, where clauses, and doesn’t fall through implicitly.
let point = (2, 0)
switch point {
case (0, 0):
print("Origin")
case (let x, 0):
print("On x-axis at \(x)")
case (0, let y):
print("On y-axis at \(y)")
case (-2...2, -2...2):
print("Near the origin")
default:
print("Somewhere else")
}
Notes:
default to catch the rest).fallthrough; each case is its own scope.case "a", "e", "i", "o", "u":.enum Direction { case north, south, east, west }
let d: Direction = .north
switch d {
case .north, .south:
print("Vertical")
case .east, .west:
print("Horizontal")
}
Swift’s pattern matching extends beyond switch:
let x, let y).1...5, ..<10, Character("a")..."z"._.where clauses: add extra conditions.let number = 42
switch number {
case let n where n.isMultiple(of: 2):
print("\(n) is even")
default:
break
}
case .some(let value) or simply case let value?.if case / guard case / for case: pattern match outside switch.if case let .some(v) = Optional(5) { print(v) }
for case let .success(value) in results {
print("Success:", value)
}
Patterns make code expressive: instead of checking and unwrapping manually, you tell the compiler the shape you expect.
These statements alter normal flow inside loops/switches/functions.
continueSkips the current iteration, moves to the next.
for n in 1...10 {
if n.isMultiple(of: 2) { continue }
print(n) // prints odd numbers
}
breakswitch: ends the case early (rarely needed, since cases don’t fall through).while true {
let cmd = readLine() ?? ""
if cmd == "quit" { break }
}
fallthroughForces execution to continue to the next switch case. Use sparingly (mainly for simple grouping logic).
let ch: Character = "a"
switch ch {
case "a":
print("First letter")
fallthrough
case "b":
print("One of the first two letters")
default:
break
}
returnExits a function/closure. Can return a value:
func square(_ x: Int) -> Int {
return x * x
}
For single-expression functions, return can be omitted: func square(_ x: Int) -> Int { x * x }.
guard (below) typically ends with a return, throw, continue, or break to satisfy flow rules.
throwSignals an error has occurred; control jumps to the nearest catch. Functions that can throw must be marked throws.
enum ValidationError: Error { case empty }
func validate(_ s: String) throws {
if s.isEmpty { throw ValidationError.empty }
}
do {
try validate("")
} catch {
print("Invalid:", error)
}
try? to convert errors into optionals, try! to assert no error (crashes if wrong).guard for early exits on failure.guardguard is Swift’s “happy path first” tool. You assert what must be true to continue; otherwise you exit.
func greet(_ name: String?) {
guard let name = name, !name.isEmpty else {
print("No name to greet"); return
}
print("Hello, \(name)!")
}
else block.name above) remain available after the guard.On Apple platforms, you often need to gate code by OS version. Swift provides compile-time syntax:
if #available(iOS 17, macOS 14, *) {
// Use new API
} else {
// Fallback for older systems
}
* means “on all other platforms, assume availability”.guard:guard #available(iOS 16, *) else {
// Provide alternative path
return
}
useNewStuff()
You can also mark declarations:
@available(iOS 15, *)
func newFeature() { /* ... */ }
Calling newFeature() from code that runs on earlier iOS requires an availability check.
enum FetchError: Error { case networkDown, badData }
func process(scores: [Int]?) throws -> Double {
// Early exit if no data
guard let scores, !scores.isEmpty else { throw FetchError.badData }
var total = 0
for score in scores {
if score < 0 { continue } // skip invalid
total += score
if total > 1_000 { break } // cap work
}
let avg = Double(total) / Double(scores.count)
switch avg {
case 0..<50: print("Low")
case 50..<80: print("Medium")
case 80...100: print("High")
default: print("Out of range")
}
return avg
}
if #available(iOS 17, *) {
// New APIs only if iOS 17+
}
This snippet shows: optional binding, guard exit, for-in with continue/break, switch with ranges, and error throwing.
if/else, switch, pattern matching (if case, guard case).for-in (preferred), while, repeat-while.guard + return/throw/break/continue.continue, break, fallthrough, return, throw.if #available, @available.
This package provides you with an easy way to show tooltips over any SwiftUI view, since Apple does not provide ...
SimpleToast is a simple, lightweight, flexible and easy to use library to show toasts / popup notifications inside iOS or ...
Create Toast Views with Minimal Effort in SwiftUI Using SSToastMessage. SSToastMessage enables you to effortlessly add toast notifications, alerts, and ...