@escaping vs non-escaping closures

Swift language Junior Swift 5.0+ iOS 17+ Reviewed By Alok Singh

Pick the fix

Storing completion in a property fails: escaping closure captures non-escaping parameter. Which fix is right?

final class Loader {
    private var onDone: (() -> Void)?
    func start(completion: () -> Void) {
        onDone = completion
    }
}
Options
Hint 1 of 1

Does the closure outlive the function call?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Mark the parameter @escaping

Correct. It is stored and called later, so it escapes.

Why not the others?
  • B Use withoutActuallyEscaping and store it. That is only safe if the closure doesn't outlive the call; storing it breaks that promise.
  • C Mark it @autoclosure. Autoclosure wraps an expression; it doesn't change escaping.
  • D Mark it @Sendable. Sendable is about thread safety, not lifetime.

30-second answer

Closure parameters are non-escaping by default: they must be called before the function returns, so the compiler knows they can't outlive the call. Mark a parameter @escaping when you store it or call it later, for example a completion handler. Escaping closures need explicit self. and are where retain cycles happen.

Practise saying it · 30 s. No recording, just a timer

Explain @escaping.

Say your answer out loud, then check which of these points you covered:

  • Non-escaping by default
  • @escaping when stored or called later
  • Watch for retain cycles

Deep dive

Non-escaping closures allow optimizations and don't need [weak self].

Optional closure parameters are escaping implicitly.

withoutActuallyEscaping lets you pass a non-escaping closure to an API that wants an escaping one, if it really doesn't escape.

async/await replaces most escaping completion handlers.

Common mistakes

  • Adding @escaping everywhere 'to make it compile'.
  • Capturing self strongly in a stored escaping closure.

Senior take & follow-ups

Seniors link @escaping to object lifetimes, not just compiler errors.

Follow-up questions

Think of your answer first, then open the hint.

  1. Why does the compiler ask for explicit self in escaping closures?

    Show hint

    To make capturing self, and possible cycles, visible.

  2. Are closures stored in properties escaping?

    Show hint

    Yes, always.

Suggest a fix if something here is wrong or out of date.