← Back to Swift Course | Chapter 7: Closures | Lesson 4 of 6

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
swift
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

markup
// 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()
}

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

markup
// 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")
}
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
  1. Forgetting to mark a closure parameter @escaping when it's stored in a property or called after the function returns -- the compiler will flag this.
  2. Assuming all closures need @escaping; a closure only needs it if it outlives the function call, e.g. stored for later or used asynchronously.
  3. Creating a strong reference cycle by capturing self strongly inside a stored escaping closure without using [weak self].
Chapter Summary
  • A closure parameter must be marked @escaping if 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 self in 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:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.