- July 29, 2025
- Mins Read
When the last parameter to a function is a closure, you can write that closure after the function’s parentheses—without the parameter label. This is called a trailing closure.
func performTask(times: Int, task: () -> Void) {
for _ in 1...times {
task()
}
}
// Call without trailing closure:
performTask(times: 3, task: {
print("Hello")
})
// Trailing closure goes outside the (…):
performTask(times: 3) {
print("Hello")
}
This reads more naturally when the closure is the main “action” you’re passing in.
Swift can infer parameter types and return types from context, and you can:
return
keyword when the body is a single expression.$0
, $1
, …) for positional parameters.let numbers = [1, 2, 3, 4, 5]
// Full form:
let doubledFull = numbers.map { (n: Int) -> Int in
return n * 2
}
// Inferred types + implicit return:
let doubledInferred = numbers.map { n in
n * 2
}
// Shorthand argument name:
let doubledShorthand = numbers.map { $0 * 2 }
UIView.animate { … }
).UIView.animate(withDuration: 0.3) {
view.alpha = 0
}
$0
, $1
, etc. is obvious.map
, filter
, sorted(by:)
, where brevity improves readability.Avoid shorthand when the closure body is complex, when you have more than 2–3 parameters, or when semantic names (from
, to
, value
) would clarify intent.
Paste this into a playground to verify you can use $0
, $1
correctly:
// Test array of strings, sort by length using shorthand:
let words = ["swift", "closure", "trailing", "syntax"]
let sortedByLength = words.sorted { $0.count < $1.count }
assert(sortedByLength == ["swift", "syntax", "closure", "trailing"])
print("Test Passed: sortedByLength == \(sortedByLength)")
// Test mapping to optionals via shorthand:
let raw = ["1", "two", "3", "4a"]
let ints = raw.compactMap { Int($0) }
assert(ints == [1, 3])
print("Test Passed: ints == \(ints)")
Test Passed: sortedByLength == ["swift", "syntax", "closure", "trailing"]
Test Passed: ints == [1, 3]
In Swift you can pass functions or closures into other functions by specifying a function type as a parameter. The syntax is:
func performOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) {
let result = operation(a, b)
print("Result is \(result)")
}
Here, operation
is a parameter whose type is a closure taking two Int
s and returning an Int
.
func add(_ x: Int, _ y: Int) -> Int {
return x + y
}
performOperation(4, 5, operation: add)
// Prints: Result is 9
performOperation(4, 5, operation: { (x, y) in
x * y
})
// Prints: Result is 20
If the last (or only) parameter is a closure, you can write it after the function call’s parentheses:
performOperation(4, 5) { x, y in
x - y
}
// Prints: Result is -1
// Define a function that applies a closure twice
func applyTwice(to value: Int, using transform: (Int) -> Int) -> Int {
return transform(transform(value))
}
// Test with a doubling closure
let double = { (x: Int) -> Int in x * 2 }
let result1 = applyTwice(to: 3, using: double)
assert(result1 == 12)
print("Test 4.1 Passed: applyTwice doubled twice == \(result1)")
Expected output:
Test 4.1 Passed: applyTwice doubled twice == 12
// Reuse applyTwice but with a trailing closure that adds 5
let result2 = applyTwice(to: 10) { $0 + 5 }
assert(result2 == 20)
print("Test 4.2 Passed: applyTwice with +5 twice == \(result2)")
Expected output:
Test 4.2 Passed: applyTwice with +5 twice == 20
With these patterns you can accept, customize, and test functions/closures passed into your Swift APIs. Feel free to extend these examples to more parameters, different return types, or even throwing closures!
1. Taking Action When a Property Changes: Property Observers Swift lets you observe and respond to changes in a property’s ...
1. Creating Your Own Structs In Swift, a struct is a value type that you define with the struct keyword. ...
1. What Is a Closure (and Why Swift Loves Them) A closure in Swift is a self-contained block of functionality ...
1. Providing Default Values for Function Parameters (Deep Dive) 1.1 Syntax and Ordering Declaration You assign a default right in ...