Statements
Statements control the flow of execution. Swift has three broad categories —
simple statements (expressions and declarations), control-flow statements
(loops and branches), and compiler-control statements. This reference
summarizes each, including defer, do, and
availability conditions.
Loop statements
Swift has three loops:
for-in— iterates a sequence, range, or collection, optionally filtered withwhere.while— evaluates the condition before each iteration.repeat-while— runs the body once, then evaluates the condition.
for n in 1...3 where n.isMultiple(of: 1) { print(n) }
while hasMore { advance() }
repeat { tick() } while running
Branch statements
if chooses between branches based on Boolean
conditions or optional/case bindings. guard
requires a condition to hold and otherwise transfers control out of the current
scope; its bindings stay in scope after the statement. switch
matches a value against patterns and must be exhaustive, with no implicit
fallthrough.
As of Swift 5.9+, if and switch can also be used as
expressions that produce a value.
guard let url = URL(string: text) else { return }
let label = switch score {
case 90...: "A"
case 80..<90: "B"
default: "?"
}
Switch cases support interval matching, tuple matching, value bindings,
where clauses, and compound cases separated by commas.
Labeled statements
A loop or branch statement can carry a label, letting
break and continue target a specific outer statement
rather than the innermost one.
search: for row in grid {
for cell in row {
if cell == target { break search }
}
}
Control transfer statements
| Statement | Effect |
|---|---|
break | End the enclosing (or labeled) loop or switch |
continue | Skip to the next loop iteration |
fallthrough | Continue into the next switch case |
return | Exit the current function, optionally with a value |
throw | Throw an error to be handled by a caller |
defer and do
A defer block runs when the current scope exits,
by any path, in reverse order of declaration — ideal for cleanup. A
do statement introduces a new scope and is the
home of error handling via catch clauses; a bare do
is also useful just to scope locals.
func read() throws {
let handle = open()
defer { handle.close() } // always runs on exit
do {
try handle.parse()
} catch let e as ParseError {
print(e)
}
}
Availability condition
An availability condition, #available, guards code
that uses APIs introduced in a newer OS; its inverse, #unavailable,
guards the older-platform path. Use them in if, guard,
and while conditions.
if #available(iOS 17, *) {
useNewAPI()
} else {
useFallback()
}
Compiler control statements
Compiler control statements are not runtime control flow — they direct
compilation. They include conditional compilation
(#if / #elseif / #else / #endif),
line-control (#sourceLocation), and diagnostic directives
(#warning("…"), #error("…")).
#if os(iOS)
import UIKit
#elseif os(macOS)
import AppKit
#endif
#warning("TODO: handle empty state")
Summary
Swift's statements give you exhaustive, fallthrough-free branching, three loop
forms, labeled control transfer, deterministic cleanup with defer,
structured error handling with do/catch, runtime API
gating with #available, and compile-time configuration with
#if directives.