Closures
Prerequisites: Parameters and argument labels
A closure is a function without a name, written inline, that you
can store in a variable or pass to another function. You've already
used them: { $0 > 20 } in the Array lessons is a closure.
Real-world analogy: a closure is an instruction slip you hand to someone along with a job — "for each parcel, check the weight like this". They decide when to follow it.
Full syntax
let double = { (n: Int) -> Int in
n * 2
}
print(double(21))
42
The parameters and return type come first, then in, then the body.
Passing a closure to a function
let names = ["Linus", "ada", "Grace"]
let sorted1 = names.sorted(by: { (a: String, b: String) -> Bool in
a.lowercased() < b.lowercased()
})
print(sorted1)
["ada", "Grace", "Linus"]
Shorter and shorter
Swift lets you trim a closure down step by step when the meaning stays clear. All of these are the same:
let names = ["Linus", "ada", "Grace"]
// Types inferred from context
let a = names.sorted(by: { x, y in x.lowercased() < y.lowercased() })
// Shorthand argument names: $0, $1, ...
let b = names.sorted(by: { $0.lowercased() < $1.lowercased() })
// Trailing closure: the closure goes after the parentheses
let c = names.sorted { $0.lowercased() < $1.lowercased() }
print(a == b && b == c)
true
A trailing closure — writing the closure after the call's parentheses — is the style you'll see most, especially in SwiftUI.
Writing a function that takes a closure
The parameter's type describes the closure: (Int) -> Void means
"takes an Int, returns nothing".
func repeatTask(times: Int, task: (Int) -> Void) {
for i in 1...times {
task(i)
}
}
repeatTask(times: 3) { pass in
print("Pass \(pass)")
}
Pass 1
Pass 2
Pass 3
Capturing values
Closures capture variables from the surrounding code and keep them alive:
func makeCounter() -> () -> Int {
var count = 0
return {
count += 1
return count
}
}
let next = makeCounter()
_ = next()
_ = next()
print(next())
3
count would normally disappear when makeCounter returns, but the
closure keeps it alive. (_ = ignores a return value you don't need.)
Common mistakes
- Over-shortening.
$0and$1are great for one-liners, but name the parameters when a closure is longer than a line or two. - Forgetting
inafter the parameter list in the full syntax.
Practice
Sort ["banana", "fig", "apple"] by word length, shortest first, using
a trailing closure.
Show solution
let words = ["banana", "fig", "apple"]
print(words.sorted { $0.count < $1.count })
["fig", "apple", "banana"]