Can a reference be weak let, or unowned and optional, and what does each do when the target dies?
Predict first
What does this print before it stops?
final class Owner { deinit { print("owner deinit") } }
final class Holder {
weak let w: Owner?
unowned let u: Owner
unowned var uo: Owner?
init(_ o: Owner) { w = o; u = o; uo = o }
}
struct Pair { weak var w: Owner?; unowned var u: Owner }
print("sizes:", MemoryLayout<Pair>.size, MemoryLayout<Owner?>.size)
func go() {
var h: Holder?
do { let o = Owner(); h = Holder(o) }
print("weak let is", h!.w == nil ? "nil" : "alive")
print("reading the unowned optional...")
print(h!.uo == nil)
print("not reached")
}
go()
- sizes: 16 8, weak let is nil, reading the unowned optional..., then a runtime error
- sizes: 16 8, weak let is nil, reading..., true, not reached
- It does not compile: weak let is not allowed
Mental model. weak is a sticky note that fades to blank when the person leaves. unowned is a phone number you promised would stay valid: dial it after they move and the call does not just fail, the whole office stops.
Both are allowed in current Swift. weak let (a weak constant) works since Swift 5.10: the reference is set once in init, can never be reassigned, but still becomes nil automatically when the target dies (the check prints nil); it documents “this link never changes” and lets the compiler treat the class as more immutable. unowned may also be applied to an Optional (unowned var uo: Owner?), which means “may be nil on purpose, but if it holds an object I promise the object outlives me”. It is not zeroed: reading it after the owner is gone traps with “Attempted to read an unowned reference but object … was already destroyed”, exactly like a non-optional unowned, and the process stops before “not reached” prints.
That asymmetry is the whole lesson: weak converts “gone” into nil, unowned converts it into a crash, whatever the type of the property. Structs may hold either (a struct with a weak and an unowned reference is 16 bytes, an optional class reference is 8). Use unowned only for relations enforced by ownership (child to parent, closure inside the owner), and prefer weak when the target’s lifetime is controlled elsewhere; Q135 gives the decision rules. In a Sendable class, a weak let of a Sendable object is how you keep a safe non-owning link without making the property mutable.
weak let is zeroed; an unowned optional is not and traps when read after the owner is gone.
Common traps
- Thinking
unowned var x: T?becomes nil. It never does; it traps. - Using
weak varwhere a constant would do. Preferweak letwhen the link never changes, so mutation of it cannot be introduced by accident.
They might follow up with
- Why is a weak property optional? Because the runtime must be able to write nil into it (Q134).
- Which Swift version first allowed
weak let? Swift 5.10; older toolchains reject it.
Related questions
- 3.2.1 What is the difference between strong, weak, unowned and unowned(unsafe)?
- 3.2.3 How do you decide between weak, unowned and strong for a back-reference?
- 3.2.5 What happens to an object’s memory while unowned references to it still exist?
- 3.2.2 Why is a weak reference optional, what can be weak, and what is the trap when reading one?
← What does copying a struct that holds class references cost, and how… Why must a pointer obtained from an array or withUnsafe… never be… →