Swift Escaping Closures
An escaping closure keeps running after the function that received it has returned. The @escaping mark on a parameter gives the function permission to store that closure for later.
Stored in a variable
The function stores the closure and returns at once. The last call runs the stored closure after the return.
var saved: (() -> Void)?
func store(_ action: @escaping () -> Void) {
saved = action
print("stored")
}
store { print("runs later") }
print("function returned")
saved?()Stored in an array
Each call appends one closure to the array. The loop runs both stored closures in order.
var handlers: [() -> Void] = []
func addHandler(_ handler: @escaping () -> Void) {
handlers.append(handler)
}
addHandler { print("first handler") }
addHandler { print("second handler") }
print(handlers.count)
for handler in handlers {
handler()
}Storing without the mark fails
This program tries to store a plain closure parameter in an outside variable. The compiler refuses it and reports the first error line below.
var stored: (() -> Void)?
func save(_ c: () -> Void) {
stored = c
}
save { print("saved") }Example
var stored: (() -> Void)?
func keep(_ action: @escaping () -> Void) {
stored = action
}
keep { print("Welcome back") }
print("Signed out")
print("Signed in again")
stored?()Key points
- A closure parameter is non-escaping by default.
- A non-escaping closure must finish its work before the function returns.
- The @escaping mark lets a function store the closure in a variable or an array.
- A stored closure runs whenever the program later calls it.
- Storing a non-escaping closure is a compile error.
In this example, keep stores its escaping closure and returns without running it. The program prints two lines first. The stored closure runs only at the final call and prints Welcome back.
Note
completion handlers for slow work are the classic escaping closure.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does the @escaping mark allow a function to do with a closure?