100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Swift

Escaping and Autoclosures in Swift

Learn what @escaping and @autoclosure mean, why closures are non-escaping by default, and when to use each attribute.

Functions & ClosuresAdvanced10 min readJul 8, 2026
Analogies

Introduction

By default, closures passed as function parameters in Swift are non-escaping, meaning they must be called before the function they were passed to returns, for memory-safety and performance reasons. Some scenarios, such as storing a closure for later or invoking it asynchronously in a completion handler, require the closure to outlive the function call. Swift's @escaping attribute marks such parameters explicitly. A related but different feature, @autoclosure, automatically wraps an expression passed as an argument into a closure, deferring its evaluation until the closure is actually called.

🏏

Cricket analogy: A commentator's live remark closure is non-escaping, spoken and gone before the over ends, but a post-match analysis closure marked @escaping is stored to replay after the game finishes; @autoclosure is like a pundit's prepared one-liner only spoken if the moment actually calls for it.

Syntax

swift
func performLater(action: @escaping () -> Void) {
    // action may be stored and called after this function returns
}

func logIfTrue(_ condition: @autoclosure () -> Bool) {
    if condition() {
        print("true")
    }
}

Explanation

A non-escaping closure is guaranteed to be called synchronously and discarded once the function returns, so Swift can optimize memory management around it. When you need to store a closure in a property, add it to an array, or call it later inside an asynchronous callback (such as a network request completion handler), you must mark the parameter @escaping, telling the compiler and readers that the closure's lifetime can extend beyond the function call. @autoclosure, by contrast, is about deferring evaluation: it lets a caller write a plain expression instead of an explicit closure, and Swift automatically wraps that expression in a closure so it is only evaluated when the parameter is actually used inside the function. This is how functions like assert(_:_:) and the ?? nil-coalescing operator avoid evaluating their second argument unless it is actually needed.

🏏

Cricket analogy: A ball-by-ball reaction closure is guaranteed synchronous and discarded once the over finishes, but a closure stored in an array of 'moments to replay after the match' must be marked @escaping since it outlives the live over; the ?? nil-coalescing default score behaves like @autoclosure, only computed if the actual score is missing.

Example

swift
var savedCompletion: (() -> Void)?

func fetchData(completion: @escaping () -> Void) {
    savedCompletion = completion // stored for later, after fetchData returns
}

func logIfTrue(_ condition: @autoclosure () -> Bool) {
    if condition() {
        print("Condition was true")
    }
}

fetchData {
    print("Data fetched!")
}
savedCompletion?()

logIfTrue(5 > 3)

Output

swift
Data fetched!
Condition was true

Key Takeaways

  • Closures are non-escaping by default; they must be called before the function they were passed to returns.
  • @escaping marks a closure parameter that may be stored or called after the function returns, such as in async callbacks.
  • @autoclosure automatically wraps a plain expression argument into a closure, deferring its evaluation.
  • @autoclosure is used by functions like assert and operators like ?? to avoid unnecessary evaluation.
  • Escaping closures often need to capture self or other references explicitly, which is important for memory management.

Practice what you learned

Was this page helpful?

Topics covered

#Swift#SwiftProgrammingStudyNotes#Programming#EscapingAndAutoclosuresInSwift#Escaping#Autoclosures#Syntax#Explanation#StudyNotes#SkillVeris