- August 28, 2025
- Mins Read
A closure is a self-contained block of functionality you can pass around and use in your code. In Swift, closures can:
Closures come in three flavors:
sorted(by:) MethodA common use of closures is with collection methods like sorted(by:), map(_:), filter(_:), and reduce(_:_:). For example, given an array of strings:
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
You can sort it in descending alphabetical order by passing a closure that compares two elements:
let descending = names.sorted { a, b in
return a > b
}
print(descending) // ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
Here, sorted(by:) expects a closure of type (String, String) -> Bool, which returns true if the first argument should come before the second.
Closure expressions let you write inline closures without the overhead of a named function. The full form is:
{ (parameters) -> ReturnType in
statements
}
->.in: separates the signature from the body.Example: a closure that adds two integers:
let add: (Int, Int) -> Int = { (x: Int, y: Int) -> Int in
return x + y
}
add(3, 5) // 8
Swift’s type inference lets you drop much of that boilerplate when the compiler already knows the expected types:
// sorted(by:) expects (String, String) -> Bool, so we can omit types:
let desc2 = names.sorted { (a, b) in
return a > b
}
Because sorted(by:)’s signature is (Element, Element) -> Bool, the compiler infers that a and b are String, and the return type is Bool.
Swift provides shorthand argument names—$0, $1, $2, …—so you can omit the parameter list entirely:
// Compare first arg ($0) to second ($1):
let desc3 = names.sorted { $0 > $1 }
Here:
$0 refers to the first parameter,$1 to the second.This is ideal for very simple closures.
If the closure body is a single expression, Swift lets you omit the return keyword:
// Full: { a, b in return a > b }
// Implicit return:
let desc4 = names.sorted { a, b in a > b }
Combine this with type inference and shorthand names, and you get the most concise form:
let desc5 = names.sorted { $0 > $1 }
When the final argument to a function is a closure, you can write it after the function call’s parentheses:
// Without trailing closure:
let desc6 = names.sorted(by: { $0 > $1 })
// With trailing closure:
let desc7 = names.sorted { $0 > $1 }
If the closure is the only argument, you can even drop the empty parentheses entirely:
let desc8 = names.sorted { $0 > $1 }
Closures can capture constants and variables from their surrounding context:
func makeIncrementer(by amount: Int) -> () -> Int {
var total = 0
return {
total += amount // captures both `total` and `amount`
return total
}
}
let incByTen = makeIncrementer(by: 10)
incByTen() // 10
incByTen() // 20
Each call to makeIncrementer creates its own total variable that the returned closure closes over.
| Feature | Full Syntax | Shorthand |
|---|---|---|
| Type annotation | { (x: Int, y: Int) -> Int in ... } |
Compiler infers from context |
| Argument list | (x, y) in ... |
$0, $1 |
| Return keyword | return expr |
Omit for single-expression bodies |
| Trailing closure | .method(arg: val, { … }) |
.method { … } |
With these tools—closure expressions, shorthand names, implicit returns, and trailing syntax—you can write concise, powerful inline behaviors in Swift. Play around with map, filter, reduce, compactMap, and flatMap next to see closures in action across the standard library!
This package provides you with an easy way to show tooltips over any SwiftUI view, since Apple does not provide ...
SimpleToast is a simple, lightweight, flexible and easy to use library to show toasts / popup notifications inside iOS or ...
Create Toast Views with Minimal Effort in SwiftUI Using SSToastMessage. SSToastMessage enables you to effortlessly add toast notifications, alerts, and ...