Escaping Closures
An escaping closure is one that's saved to be used later, after the function that created it has already finished and gone away.
Syntax
func functionName(_ completion: @escaping () -> Void) {
storage.append(completion) // stored and called later
}
func other(_ action: () -> Void) {
action() // non-escaping: run before returning
}
Declaring an Escaping Closure Parameter
Marking a closure parameter @escaping allows it to be stored (for example, in an array) and invoked later, even after the function that received it has already returned.
Example: Declaring an Escaping Closure Parameter
// Declare a mutable variable `savedCompletions` (a `[() -> Void]`), initialized to `[]`
var savedCompletions: [() -> Void] = []
// Define the function `saveCompletion` taking `completion`
func saveCompletion(_ completion: @escaping () -> Void) {
// Append `completion` to `savedCompletions`
savedCompletions.append(completion)
}
saveCompletion { print("Completion 1 ran") }
saveCompletion { print("Completion 2 ran") }
// Loop over `savedCompletions`, binding each item to `completion`
for completion in savedCompletions {
completion()
}
Login to try C/C++/Java/PHP code in the editor
Non-Escaping by Default
Closures are non-escaping by default, meaning they must be called before the function returns -- this is more memory-efficient and is what makes something like .map's closure argument safe without @escaping.
Example: Non-Escaping by Default
// Define the function `runImmediately` taking `action`
func runImmediately(_ action: () -> Void) {
// Print "About to run" to the console
print("About to run")
action()
// Print "Finished running" to the console
print("Finished running")
}
runImmediately {
// Print "Running the action now" to the console
print("Running the action now")
}
Login to try C/C++/Java/PHP code in the editor
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the
view already swaps in the hi_ translation fields (or blanks these
out if untranslated), so this renders correctly for both languages
without a lang_code check here. #}
Common Mistakes
- Forgetting to mark a closure parameter
@escapingwhen it's stored in a property or called after the function returns -- the compiler will flag this. - Assuming all closures need
@escaping; a closure only needs it if it outlives the function call, e.g. stored for later or used asynchronously. - Creating a strong reference cycle by capturing
selfstrongly inside a stored escaping closure without using[weak self].
Chapter Summary
- A closure parameter must be marked
@escapingif it's stored or called after the function returns. - Non-escaping closures (the default) must be used only during the function call itself.
- Escaping closures are common for completion handlers and asynchronous callbacks.
- Capturing
selfin a stored escaping closure risks a retain cycle unless handled carefully.
🔒
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: