- July 30, 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!
PermissionsSwiftUI displays and handles permissions in SwiftUI. It is largely inspired by SPPermissions. The UI is highly customizable and resembles an Apple style. ...
Introduction PagerTabStripView is the first pager view built in pure SwiftUI. It provides a component to create interactive pager views ...
1. Taking Action When a Property Changes: Property Observers Swift lets you observe and respond to changes in a property’s ...