Weak vs Unowned
Two ways to reference something without keeping it alive — and the crash that separates them.
Both weak and unowned reference an object without increasing its strong count, so neither keeps the object alive. The difference is entirely about what happens when the object dies first.
A weak reference is automatically set to nil at that moment. It must therefore be declared var and optional, and you check it before use.
An unowned reference is not zeroed. It keeps pointing where the object used to be. Using it after the object is gone traps and terminates the process.
So the choice isn't safety versus speed. It's a statement about lifetime: unowned means "I guarantee this outlives me", and the crash is what happens when your guarantee turns out to be wrong.
unowned fits a genuine lifetime guarantee; weak fits anything less certain.final class Customer { let name: String var card: CreditCard? // strong: customer owns the card init(name: String) { self.name = name } deinit { print("Customer gone") }}
final class CreditCard { let number: String unowned let customer: Customer // a card can't outlive its customer init(number: String, customer: Customer) { self.number = number self.customer = customer } deinit { print("Card gone") }}
// weak, by contrast, must be a var and optionalfinal class Screen { weak var delegate: ScreenDelegate? // delegate may vanish at any time}protocol ScreenDelegate: AnyObject {}
Show all 22 linesShow less
final class Customer { let name: String var card: CreditCard? // strong: customer owns the card init(name: String) { self.name = name } deinit { print("Customer gone") }}
final class CreditCard { let number: String unowned let customer: Customer // a card can't outlive its customer init(number: String, customer: Customer) { self.number = number self.customer = customer } deinit { print("Card gone") }}
// weak, by contrast, must be a var and optionalfinal class Screen { weak var delegate: ScreenDelegate? // delegate may vanish at any time}protocol ScreenDelegate: AnyObject {}A weak reference becomes nil when its target is deallocated. An unowned reference keeps pointing at freed memory and traps if used.
Neither reference contributes to the strong count, so the object can die.
- Neither reference contributes to the strong count, so the object can die.
- The weak reference is zeroed automatically — you check it and move on.
- The unowned reference is left dangling. Touching it terminates the process.
Under the hood
Zeroing isn't free. Every weak reference to an object is registered in a side table keyed by that object, so when it deallocates the runtime can walk the table and nil them all. That's an extra allocation for the table and a lock around access, and reading a weak reference means loading through it and retaining the result so it can't die mid-expression.
unowned skips the side table. Instead the object keeps a separate *unowned count*, and while that count is above zero the memory isn't returned to the allocator even after deinit has run — the object becomes a zombie holding its own slot. That's what makes the failure a clean deterministic trap rather than a read of whatever was allocated there next.
unowned(unsafe) drops even that, giving you a raw dangling pointer with undefined behaviour on access. It exists for interop and hot paths; it should be rare.
Quick check
Why must a weak reference always be a var and optional?
- Because ARC needs to reassign it to nil when the object deallocates
- Because weak references are always to classes
- Because the compiler can't infer the type otherwise
- It doesn't have to be — `weak let` is legal
Reveal answer
Because ARC needs to reassign it to nil when the object deallocates
Zeroing is the defining behaviour of weak: when the object dies, the runtime writes nil into every weak reference to it. That requires the reference to be mutable and to have nil in its domain, so var and optional are both forced. unowned isn't zeroed, which is exactly why unowned let is fine.
Interview question
Walk me through choosing between weak and unowned for a specific relationship.
Think first, then reveal
I ask one question: can I state an invariant that guarantees the referenced object outlives this reference, and is that invariant enforced by code I control?
If yes — the classic case being a child object created by its parent, stored only by that parent, and unreachable once the parent is gone — unowned is honest. It documents the guarantee in the type, avoids an optional that would always succeed, and if I've got the invariant wrong the trap tells me loudly and immediately rather than hiding.
If the answer is no, weak. And "no" covers more than people expect: anything whose lifetime the system controls, anything reachable from a collection someone else mutates, anything torn down asynchronously. A delegate is the standard example — the delegating object has no idea when its delegate goes away, so weak var delegate is the only defensible choice.
The asymmetry that decides ties: an unnecessary weak costs an optional unwrap and a small read overhead. An incorrect unowned costs a crash on a user's device, in a scenario you didn't reproduce. Those aren't comparable, so I default to weak under uncertainty and treat unowned as something I have to justify.
What an interviewer listens for
- Frames it as an invariant you can state and enforce, not a preference
- Gives the parent-owns-child case as the legitimate unowned shape
- Identifies delegates and system-owned lifetimes as weak territory
- Reasons explicitly about the asymmetric cost of being wrong
Key takeaway
weak becomes nil when the object dies; unowned becomes a trap. Pick unowned only when you can state the invariant that makes the object's longer life certain.