Crash Courses · Masters
Control Flow, Functions & Closures
Write expressive Swift control flow with if/guard/switch/for, design functions with argument labels and default parameters, and master closures.
16 min read+170 XP on completionCert: Swift Crash Course
Tap any word in the text below to start reading from there.
Control Flow, Functions & Closures
Control Flow: if, guard, switch
// if/else — no parentheses required around condition
let score = 87
let grade: String
if score >= 90 { grade = "A" }
else if score >= 80 { grade = "B" }
else if score >= 70 { grade = "C" }
else { grade = "F" }
// Ternary
let status = score >= 60 ? "Pass" : "Fail"
// guard — early exit (same as guard let but for conditions)
func processScore(_ score: Int) -> String {
guard score >= 0 && score <= 100 else {
return "Invalid score"
}
return "Valid: \(score)"
}Swift switch — exhaustive and powerful:
// Must handle all cases (or use default:)
let day = "Wednesday"
switch day {
case "Saturday", "Sunday":
print("Weekend")
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday":
print("Weekday")
default:
print("Unknown")
}
// Range matching
let temp = 23
switch temp {
case ..<0: print("Freezing")
case 0..<15: print("Cold")
case 15..<25: print("Comfortable")
case 25...: print("Hot")
default: break
}
// Tuple pattern matching
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 (let x, let y): print("Point at (\(x), \(y))")
}---
Functions: Labels and Parameters
Swift functions have argument labels (external) and parameter names (internal):
// External label "to", internal name "recipient"
func sendEmail(to recipient: String, subject: String, body: String) {
print("To: \(recipient)")
print("Subject: \(subject)")
print("\(body)")
}
// Called with labels:
sendEmail(to: "alice@example.com", subject: "Hello", body: "How are you?")
// No external label with _
func multiply(_ a: Int, by b: Int) -> Int {
return a * b
}
let result = multiply(5, by: 3) // 15
// Default parameter values
func greet(_ name: String, prefix: String = "Hello") -> String {
return "\(prefix), \(name)!"
}
print(greet("Jordan")) // Hello, Jordan!
print(greet("Jordan", prefix: "Hey")) // Hey, Jordan!
// Variadic parameters
func sum(_ numbers: Int...) -> Int {
return numbers.reduce(0, +)
}
print(sum(1, 2, 3, 4, 5)) // 15
// inout — modify a parameter in place
func doubleInPlace(_ n: inout Int) {
n *= 2
}
var x = 5
doubleInPlace(&x)
print(x) // 10---
Closures
A closure is a function without a name:
// Full closure syntax
let double: (Int) -> Int = { (n: Int) -> Int in
return n * 2
}
// Shorthand argument names ($0 = first arg, etc.)
let double2: (Int) -> Int = { $0 * 2 }
// Trailing closure syntax when last argument
let numbers = [5, 3, 8, 1, 9, 2, 7]
let sorted = numbers.sorted(by: { a, b in a < b })
let sortedShort = numbers.sorted { $0 < $1 } // trailing closure
let doubled = numbers.map { $0 * 2 } // [10, 6, 16, 2, 18, 4, 14]
let evens = numbers.filter { $0 % 2 == 0 } // [8, 2]
let total = numbers.reduce(0) { $0 + $1 } // 35
let totalShort = numbers.reduce(0, +) // 35 (operator as closure)
print(doubled) // [10, 6, 16, 2, 18, 4, 14]
print(evens) // [8, 2]
print(total) // 35Capturing values:
func makeCounter(start: Int = 0) -> () -> Int {
var count = start
return {
count += 1
return count
}
}
let counter = makeCounter()
print(counter()) // 1
print(counter()) // 2
print(counter()) // 3---
@escaping Closures
When a closure is stored beyond the function's lifetime, mark it @escaping:
class DataLoader {
var completionHandlers: [() -> Void] = []
// @escaping: closure stored in array, outlives loadData()
func loadData(completion: @escaping () -> Void) {
completionHandlers.append(completion)
// In a real app: URLSession.shared.dataTask(...)
// Later, the completion is called when data arrives
}
func simulateDataLoaded() {
completionHandlers.forEach { $0() }
completionHandlers.removeAll()
}
}
let loader = DataLoader()
loader.loadData {
print("Data loaded!")
}
loader.simulateDataLoaded() // "Data loaded!"---
Loops
// for-in with range
for i in 1...5 {
print(i) // 1 2 3 4 5
}
for i in 1..<5 { // half-open range (1, 2, 3, 4)
print(i)
}
// for-in with array
let fruits = ["apple", "banana", "cherry"]
for fruit in fruits {
print(fruit)
}
// enumerated — get index + value
for (index, fruit) in fruits.enumerated() {
print("\(index): \(fruit)")
}
// while
var n = 1
while n <= 100 {
n *= 2
}
print(n) // 128 — first power of 2 > 100
// repeat-while (do-while equivalent)
var attempts = 0
repeat {
attempts += 1
} while attempts < 3
print(attempts) // 3Reading progress
0% read
In this module
Argument Label
Closure
Trailing Closure
Shorthand Arguments
0%