This page has moved to swiftly.dev/closures! The archive below will not be updated.
Swift closures are blocks of functionality that are self-contained, and can be passed around. They are similar to blocks in C and Objective-C, as well as lambdas in other languages. Functions are a special type of closures.
@escaping
closure parameterClosures can be defined with closure expression syntax, which has the general form:
{ (parameters) -> return type in statements }
Using closure expression syntax:
let sortedInts = [4, 30, 7, 9, 1].sorted(by: { (x: Int, y: Int) -> Bool in
return x < y
})
Because this closure is the last and only argument,1 trailing closure syntax may be used and the parentheses are optional:
let sortedInts = [4, 30, 7, 9, 1].sorted { (x: Int, y: Int) -> Bool in
return x < y
}
When the argument and/or return types are known, the type annotations are optional:
let sortedInts = [4, 30, 7, 9, 1].sorted { x, y in return x < y }
Also, closure parameters can be referenced by position instead of by name:
let sortedInts = [4, 30, 7, 9, 1].sorted { $0 < $1 }
A closure can be stored as a variable and used later. Using closure expression syntax:
let myClosure = { (x: Int, y: Int) -> Bool in
return x < y
}
let sortedInts = [4, 30, 7, 9, 1].sorted(by: myClosure)
A function is a type of closure, so a closure can be stored as a function to be used later.
func myClosure(x: Int, y: Int) -> Bool {
return x < y
}
let sortedInts = [4, 30, 7, 9, 1].sorted(by: myClosure)
A function can be created with a closure parameter:
func multiply(x: Int, y: Int, completion: (Int) -> Void) {
completion(x * y)
}
multiply(x: 5, y: 6) { print($0) } // Output: 30
A closure parameter may be optional:
func multiply(x: Int, y: Int, completion: ((Int) -> Void)?) {
completion?(x * y)
}
multiply(x: 5, y: 6) { print($0) } // Output: 30
It may have labeled arguments for readability:2
func multiply(x: Int, y: Int, completion: (_ result: Int) -> Void) {
completion(x * y)
}
multiply(x: 5, y: 6) { print($0) } // Output: 30
Or multiple arguments:
func multiply(x: Int, y: Int, completion: (Int, Error?) -> Void) {
completion(x * y, nil)
}
multiply(x: 5, y: 6) { print($1 ?? $0) } // Output: 30
Or no arguments:
func multiply(x: Int, y: Int, completion: () -> Void) {
completion()
}
multiply(x: 5, y: 6) { } // Does nothing
To improve readability and reduce duplicate code, a closure typealias may be used:
typealias MultiplyCompletion = (_ result: Int, _ error: Error?) -> Void
func multiply(x: Int, y: Int, completion: MultiplyCompletion) {
completion(x * y, nil)
}
multiply(x: 5, y: 6) { print($1 ?? $0) } // Output: 30
@escaping
closure parameterAn escaping closure can be called even after the function has returned:3
func multiplyRemotely(x: Int, y: Int, completion: @escaping (Int) -> Void) {
APIManager.shared.multiply(x: x, y: y, completion: completion)
}
multiplyRemotely(x: 5, y: 6) { print($0) }
// Output: 30
When a closure is the last parameter of a function, it is called a trailing closure. ↩
It is commonly asked why the argument names don’t appear in the closure call, like completion(result: x * y)
. The reason for this is that as of Swift 3, closure argument labels are no longer part of the closure type. ↩
This makes it possible to make a network call to a remote server, return the function, then have the closure get executed when the server response is received. The benefit of this is that the rest of the execution of the function, and subsequently parent functions, do not have to get blocked while the app waits for a response. ↩