Closures
A closure is a function literal. Swift has the cleanest closure syntax in the C-family: type-inference, trailing-closure syntax, shorthand argument names ($0, $1), implicit returns.
Closures — the four shapes
EXAMPLE
// 1) Full form
let adder: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
return a + b
}
// 2) Inferred parameter types
let adder2: (Int, Int) -> Int = { a, b in a + b }
// 3) Shorthand argument names
let adder3: (Int, Int) -> Int = { $0 + $1 }
// 4) Trailing closure — the syntactic unlock
let nums = [1, 2, 3, 4, 5]
let doubled = nums.map { $0 * 2 }
let evens = nums.filter { $0.isMultiple(of: 2) }
let total = nums.reduce(0, +)
// 5) Multiple trailing closures (Swift 5.3+)
UIView.animate(withDuration: 0.3) {
self.label.alpha = 0
} completion: { _ in
self.label.removeFromSuperview()
}
// 6) Capture lists — control what closure captures
class Vote {
var count = 0
func register(_ block: @escaping () -> Void) {}
func setup() {
register { [weak self] in // weak — avoid retain cycle
self?.count += 1
}
register { [unowned self] in // unowned — guarantees nil-safe
self.count += 1
}
}
}
// 7) @escaping — closure outlives the function call
func fetch(_ url: URL, then: @escaping (Data) -> Void) {
URLSession.shared.dataTask(with: url) { data, _, _ in
guard let data else { return }
then(data)
}.resume()
}
// 8) @autoclosure — defer evaluation
func require(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String) {
if !condition() {
fatalError(message())
}
}
require(user != nil, "user must be signed in") // message only built on failure
// 9) Async closures
func handle(_ work: @escaping () async throws -> Int) {
Task {
let n = try await work()
print(n)
}
}
handle { try await fetchUserCount() }
// 10) Higher-order closures with proper type inference
let users = ["Ada", "Bo", "Cy"]
users.sorted { $0.count < $1.count }
Why it matters
Trailing-closure syntax + shorthand argument names make Swift APIs read like English. Lean on them, and the imperative loop with explicit names almost disappears from your code.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
let nums = [1, 2, 3, 4]
let doubled = nums.map { $0 * 2 }
let evens = nums.filter { $0 % 2 == 0 }
let total = nums.reduce(0, +)
Try it Yourself »
Discussion
Loading…