iosNudge

What is the difference between strong, weak and unowned references?

EasyAsked oftenMemory & ARC 3 min read

TL;DR

  • strong (default): keeps the object alive.
  • weak: does not keep it alive. It is always optional and becomes nil when the object is freed.
  • unowned: does not keep it alive. It is not optional. Using it after the object is freed crashes.

Use weak when the other object may disappear first. Use unowned only when it is guaranteed to live at least as long.

Strong

final class Owner {
    var dog: Dog?        // strong by default
}

As long as owner.dog points to the dog, the dog stays in memory. Most references should be strong.

Weak

final class Dog {
    weak var owner: Owner?     // must be var and optional
}

var owner: Owner? = Owner()
let dog = Dog()
dog.owner = owner
owner = nil
print(dog.owner)               // nil, the owner was freed

Rules:

  • Must be an optional type.
  • Usually a var. Since Swift 6.2 you can also write weak let; it still becomes nil when the object is freed.
  • Only works with class types (and class-bound protocols).

The delegate pattern

protocol ListViewDelegate: AnyObject {
    func didSelect(row: Int)
}

final class ListView {
    weak var delegate: ListViewDelegate?
}

The view controller owns the list view. The list view points back to the controller weakly. No cycle.

AnyObject is required. Without it, the protocol could be adopted by a struct, and weak would not make sense.

Unowned

final class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) { self.name = name }
}

final class CreditCard {
    unowned let customer: Customer    // a card never outlives its customer
    init(customer: Customer) { self.customer = customer }
}

let ana = Customer(name: "Ana")
ana.card = CreditCard(customer: ana)

unowned is not optional. You do not need to unwrap it. But if the customer is freed and the card is still used, the app crashes:

Fatal error: Attempted to read an unowned reference but object was already deallocated

Comparison

strongweakunowned
Keeps object aliveYesNoNo
OptionalCan be eitherAlwaysNo (can be unowned var x: T?)
When object is freed—Becomes nilDangling, crash on access
CostRetain/releaseSide table, slightly slowerCheap
Typical useOwnershipDelegates, parent links, [weak self]Child that cannot outlive parent

In closures

final class SearchViewModel {
    var results: [String] = []
    var onUpdate: (() -> Void)?

    func bind() {
        onUpdate = { [weak self] in
            guard let self else { return }
            print(self.results.count)
        }
    }
}

[weak self] is the safe default for stored or long-living closures. [unowned self] is fine only when the closure cannot outlive self, for example a lazy var closure used only by the object itself.

unowned(unsafe)

unowned(unsafe) let parent: Node

No safety check at all. Using it after the object is freed reads random memory. It exists for rare performance cases. Avoid it in app code.

How to choose

  1. Does this object own the other one? Use strong.
  2. Can the other object be freed while this one still exists? Use weak.
  3. Is the other object guaranteed to outlive this one, and you want no optional? unowned.

When in doubt, choose weak. A nil is easier to handle than a crash.

Common follow-up questions

  • Can you use weak with a struct? No. Structs are value types. There is no shared object to point to weakly.
  • Why are IBOutlets often weak? The view hierarchy already owns subviews strongly. A weak outlet avoids holding a second strong reference. Strong outlets are also fine today.
  • Is weak slower than unowned? A little. Weak references use a side table and an atomic load. The difference matters only in very hot code.
  • What happens to a weak reference in a collection? [weak Foo] is not valid. Wrap it: struct Weak<T: AnyObject> { weak var value: T? }, or use NSHashTable.weakObjects().
  • Does weak fix all retain cycles? It fixes the cycle if you put it on the right link. Use the memory graph debugger to check.