1.5 · Closures, escaping, capture lists

A closure is a function plus the environment it captured. Every retain cycle and every “why did it print the old value?” question lives in that sentence.

Mental model. Capturing a variable shares the box. Capturing with [x] takes a snapshot. Capturing self strongly keeps the object alive.

Escaping and lifetime

How long a closure lives, and what it keeps alive.

  1. Escaping vs non-escaping closures? 1.5.1 · L1
    Non-escaping (the default for parameters) is guaranteed to be called before the function returns. The compiler can skip retains, keep captures on the stack…
  2. guard let self = self else { return } inside a closure — what does it do to ARC? 1.5.2 · L3
    It promotes the weak reference to a strong local for the remainder of the scope. That means self cannot deallocate while the body runs — usually exactly what…
  3. Why are closures called reference types? What is a closure context? 1.5.3 · L5
    A closure is (conceptually) a heap object holding a function pointer plus captured values — the closure context. The compiler optimizes it away when it can…

Capture lists

What a closure holds on to, and how strongly.

  1. What does a capture list like [weak self], [unowned self], [self], or [foo] actually do? 1.5.4 · L2
    A capture list decides how and when names are captured, at closure creation time: [weak self] — self becomes an optional weak reference; no retain, no cycle.…
  2. Why does this print the new city without a capture list, and the old one with [city]? 1.5.5 · L2
    city is a struct stored in a variable. A closure that mentions city without a capture list captures the variable slot — so it reads whatever value is there…
  3. unowned var view = UIView() then print(view) — what happens? 1.5.6 · L2
    The UIView() has no strong owner. unowned does not retain, so the instance is deallocated immediately. Reading view afterwards is undefined behaviour — in…

Closure-powered syntax

Language features built on closures.

  1. What is @autoclosure? When is it justified? 1.5.7 · L2
    @autoclosure turns an expression argument into a closure automatically. It is why assert(condition) does not evaluate the message on the success path, and why…
  2. What is a result builder (@ViewBuilder, @CommandsBuilder)? 1.5.8 · L3
    A type with static methods like buildBlock, buildOptional, buildEither, and buildExpression. The compiler rewrites a block of statements into calls to those…

More in Swift language