How do you decide between weak, unowned and strong for a back-reference?

3.2.3 · L2 · Interview

Predict first

What does this print?

final class Customer {
    var card: Card?
    deinit { print("customer gone") }
}
final class Card {
    unowned let owner: Customer
    init(_ c: Customer) { owner = c }
    deinit { print("card gone") }
}

var c: Customer? = Customer()
c!.card = Card(c!)
c = nil
  • Nothing, it leaks
  • customer gone, card gone
  • card gone, customer gone

Mental model. A card cannot outlive the customer it belongs to, so it may point at the customer without worrying. A visitor’s badge may outlive the host, so it needs a way to say “host left”.

Draw the ownership tree: every object has one clear owner that holds it strongly. A reference against that direction (child to parent, delegate to owner, observer to subject) must not be strong, or you create a cycle. Then ask whether the back-reference can ever be used after its target is gone.

If the holder cannot exist without its target by construction, such as a credit card that is always created for one customer and dies with it, use unowned: it is non-optional and documents the invariant. If the two lifetimes are independent, such as a delegate that may be replaced or a parent that can be released first, use weak. When in doubt choose weak: a surprise nil is handled, a surprise unowned read is a crash.

The customer owns the card strongly; the card points back unowned. Releasing the customer runs its deinit, then releases the card.

Common traps

  • Choosing unowned because “it should always be there”. Reality is full of teardown orders you did not plan for.
  • Weak everywhere. Hiding ownership makes objects vanish unexpectedly. Keep one strong owner.

They might follow up with

  • What about a closure capturing self? The same rule applies; see the capture-list questions in the closures section.
  • How do you verify the invariant? A unit test that deallocates the owner while the holder is still around, or a deinit log.

Related questions

  • 3.2.1 What is the difference between strong, weak, unowned and unowned(unsafe)?
  • 3.2.5 What happens to an object’s memory while unowned references to it still exist?
  • 3.3.1 What is a retain cycle, and how do you find and fix one?

← Why is a weak reference optional, what can be weak, and what is the…   What is unowned(unsafe), and when would you ever use it? →