---
title: 'Strong, Weak and Unowned References'
source: 'https://academia.sh/en/courses/swift/strong-weak-and-unowned-references'
course: 'The Swift Language'
language: en
updated: '2026-10-21T05:03:12+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Recognizes a retain cycle formed by two classes holding each other strongly from the deinit output'
    - 'Breaks the cycle by making one reference weak and observes the weak reference become nil when its object is gone'
    - 'Binds an unowned reference to the side that lives longer'
    - 'Distinguishes weak from unowned by reading after the object is gone'
---

# Strong, Weak and Unowned References

Measures that deinit never runs when two classes hold each other strongly, that weak and unowned break the cycle, and that an unowned reference cannot be read once its object is gone.

In the previous lesson the reference count dropped to zero and `deinit` ran. The count reaching zero was a condition, not a guarantee. If two class instances hold each other with **strong references**, each one keeps the other's counter one above zero, and both stay alive even when every outside name has been released. This situation is called a **retain cycle**. This lesson builds the cycle, breaks it in two ways, and measures when the `deinit` body runs in each.

There are two tools for breaking it. A **weak reference (`weak`)** does not hold the instance: it does not raise the counter, and it becomes `nil` on its own when the instance it points to is destroyed, so it is always an optional `var`. An **unowned reference (`unowned`)** also does not raise the counter, but it never becomes `nil` and does not have to be optional; in return it asks for a promise that the instance it points to will outlive the holder. `Probe` is given as in the previous lesson.

```swift
// Probe.swift — records when an expression is evaluated
final class Probe {
    let label: String
    private(set) var evaluations = 0
    private(set) var uses = 0
    private var evaluatedBeforeUse = false

    init(_ label: String) {
        self.label = label
    }

    func eval<T>(_ value: T) -> T {
        evaluations += 1
        if uses == 0 { evaluatedBeforeUse = true }
        return value
    }

    func use<T>(_ access: () -> T) -> T {
        uses += 1
        return access()
    }

    var moment: String {
        if evaluations == 0 { return "never" }
        if evaluations > 1 { return "on-every-use" }
        return evaluatedBeforeUse ? "immediately" : "on-first-use"
    }

    func report() {
        print("\(label): \(evaluations) evaluations, \(uses) uses -> \(moment)")
    }
}

func tally(_ probes: [Probe]) {
    for moment in ["immediately", "on-first-use", "on-every-use", "never"] {
        let count = probes.filter { $0.moment == moment }.count
        print("\(moment): \(count)")
    }
}
```


## The Retain Cycle

The two measured classes are `Account` and `Profile`. The `deinit` body of each prints a line and notifies the shared `Probe` through `eval`. `Account` holds a `Profile`, and `Profile` holds an `Account`; both use the default, that is, strong, reference. In each round two instances are built, linked to each other, and then both are set to `nil`. The outside names are released this way.

```swift
// main.swift — two classes hold each other strongly
final class Account {
    let name: String
    let owner: Probe
    var profile: Profile?

    init(_ name: String, owner: Probe) {
        self.name = name
        self.owner = owner
    }

    deinit {
        print("deinit account \(name)")
        _ = owner.eval(name)
    }
}

final class Profile {
    let title: String
    let owner: Probe
    var account: Account?

    init(_ title: String, owner: Probe) {
        self.title = title
        self.owner = owner
    }

    deinit {
        print("deinit profile \(title)")
        _ = owner.eval(title)
    }
}

let cyclic = Probe("retain-cycle")

for round in 1...2 {
    var account: Account? = Account("account-\(round)", owner: cyclic)
    var profile: Profile? = Profile("profile-\(round)", owner: cyclic)
    account?.profile = profile
    profile?.account = account
    _ = cyclic.use {
        account = nil
        profile = nil
    }
    print("released \(round): \(cyclic.evaluations) deinit")
}

cyclic.report()
```

```
released 1: 0 deinit
released 2: 0 deinit
retain-cycle: 0 evaluations, 2 uses -> never
```

In both rounds the `deinit` count after the release is zero, and no `deinit` line ever appears. Because each instance is held by the other's property, both counters stay at one or higher. `retain-cycle` records two uses and zero evaluations, and the rule says `never`. This lesson's moment is therefore **never**: the `deinit` body is not evaluated at any moment. Nothing reports an error, either. The two instances in the cycle stay in memory until the end of the program.

## Breaking It with a Weak Reference

To break the cycle, the reference on only one of the two sides is made weak. The second measurement defines the `Profile.account` property as `weak var` and changes nothing else. This time the instances are released in two steps: first `account`, then `profile`. After each step `profile?.account` is read and the `deinit` count is printed.

```swift
// main.swift — one side holds weakly
final class Account {
    let name: String
    let owner: Probe
    var profile: Profile?

    init(_ name: String, owner: Probe) {
        self.name = name
        self.owner = owner
    }

    deinit {
        print("deinit account \(name)")
        _ = owner.eval(name)
    }
}

final class Profile {
    let title: String
    let owner: Probe
    weak var account: Account?

    init(_ title: String, owner: Probe) {
        self.title = title
        self.owner = owner
    }

    deinit {
        print("deinit profile \(title)")
        _ = owner.eval(title)
    }
}

let broken = Probe("weak-reference")

for round in 1...2 {
    var account: Account? = Account("account-\(round)", owner: broken)
    var profile: Profile? = Profile("profile-\(round)", owner: broken)
    account?.profile = profile
    profile?.account = account
    print("linked: \(profile?.account == nil ? "nil" : "set")")
    _ = broken.use { account = nil }
    print("account released: \(profile?.account == nil ? "nil" : "set"), \(broken.evaluations) deinit")
    _ = broken.use { profile = nil }
    print("profile released: \(broken.evaluations) deinit")
}

broken.report()
```

```
linked: set
deinit account account-1
account released: nil, 1 deinit
deinit profile profile-1
profile released: 2 deinit
linked: set
deinit account account-2
account released: nil, 3 deinit
deinit profile profile-2
profile released: 4 deinit
weak-reference: 4 evaluations, 4 uses -> on-every-use
```

After linking, `profile?.account` is set. When the `account` name is released, no strong reference to the `Account` instance remains: because `profile.account` is weak, it had not raised the counter. The line `deinit account account-1` appears immediately, and the read that follows gives `nil`; a weak reference becomes `nil` on its own at the moment the instance it points to is destroyed. The `Profile` instance, on the other hand, is still held by the `profile` name, so it stays alive, and the `deinit profile` line appears only when that name is released. Four `deinit` bodies ran in two rounds, and `weak-reference` says `on-every-use`.

## Breaking It with an Unowned Reference

A weak reference says that the instance may disappear. If a relationship does not run in that direction, that is, if a `Card` will never exist without a `Customer`, the reference is written as `unowned let`. The third measurement builds this relationship: `Customer` holds an optional `card`, and `Card` carries an `unowned let customer`. The customer holds the card, and the card does not hold the customer. The measurement releases only the customer name.

```swift
// main.swift — an unowned reference binds to the longer-lived side
final class Customer {
    let name: String
    let owner: Probe
    var card: Card?

    init(_ name: String, owner: Probe) {
        self.name = name
        self.owner = owner
    }

    deinit {
        print("deinit customer \(name)")
        _ = owner.eval(name)
    }
}

final class Card {
    let number: String
    let owner: Probe
    unowned let customer: Customer

    init(_ number: String, customer: Customer, owner: Probe) {
        self.number = number
        self.customer = customer
        self.owner = owner
    }

    deinit {
        print("deinit card \(number)")
        _ = owner.eval(number)
    }
}

let bound = Probe("unowned-reference")

for round in 1...2 {
    var customer: Customer? = Customer("customer-\(round)", owner: bound)
    if let current = customer {
        current.card = Card("card-\(round)", customer: current, owner: bound)
        print("card owner: \(current.card?.customer.name ?? "none")")
    }
    _ = bound.use { customer = nil }
    print("released \(round): \(bound.evaluations) deinit")
}

bound.report()
```

```
card owner: customer-1
deinit customer customer-1
deinit card card-1
released 1: 2 deinit
card owner: customer-2
deinit customer customer-2
deinit card card-2
released 2: 4 deinit
unowned-reference: 4 evaluations, 2 uses -> on-every-use
```

In every round the `deinit customer` line comes before the `deinit card` line. When the customer is released, its counter drops to zero, the `deinit` body runs, its properties are then released, and the card's only strong reference goes with them. What breaks the cycle in this chain is that the card does not hold the customer strongly; `unowned` expresses this without making the reference optional. `unowned-reference` records two uses and four evaluations, two `deinit` bodies run in every round, and the rule says `on-every-use`.

## The Delegate Pattern

The most common place for a weak reference is the delegate pattern: an object stores a second object that it will notify when its work is finished, while the notified object already holds the object doing the work. Strong references in both directions would build a retain cycle. This measurement uses the `weak var delegate` property of the `Worker` class, and `Reporter` holds the `Worker` strongly. At the end of the round only the `reporter` name is released, and the `worker` name stays in hand.

```swift
// main.swift — the delegate is weak, the worker is strong
final class Reporter {
    let name: String
    let owner: Probe
    let worker: Worker

    init(_ name: String, owner: Probe) {
        self.name = name
        self.owner = owner
        worker = Worker()
        worker.delegate = self
    }

    deinit {
        print("deinit reporter \(name)")
        _ = owner.eval(name)
    }
}

final class Worker {
    weak var delegate: Reporter?
}

let handedOver = Probe("delegate")
for round in 1...2 {
    var reporter: Reporter? = Reporter("reporter-\(round)", owner: handedOver)
    let worker = reporter!.worker
    print("delegate \(worker.delegate?.name ?? "nil")")
    _ = handedOver.use { reporter = nil }
    print("released: delegate \(worker.delegate?.name ?? "nil"), \(handedOver.evaluations) deinit")
}

handedOver.report()
```

```
delegate reporter-1
deinit reporter reporter-1
released: delegate nil, 1 deinit
delegate reporter-2
deinit reporter reporter-2
released: delegate nil, 2 deinit
delegate: 2 evaluations, 2 uses -> on-every-use
```

After linking, `worker.delegate` gives the name of the reporter. When the `reporter` name is released, no strong reference to the `Reporter` instance remains: because `Worker` holds it weakly, it had not raised the counter. The line `deinit reporter reporter-1` appears immediately, and the read that follows gives `nil`. The `worker` keeps living because it is held by the `worker` name; although `Reporter` held it in a property, `Reporter` itself is gone, so the `Worker`'s only remaining share is the outside name. The pattern relies on this asymmetry: the notified object does not have to outlive the notifier, and the notifier learns that the notified object is gone by reading `nil`. This is why a delegate property is always written as an optional value and checked before every use. Two `deinit` bodies run in two rounds, and `delegate` says `on-every-use`.

## Weak and Unowned Reads

As long as the instance they point to is alive, the two reference forms give the same value. The difference begins after the instance is gone. This measurement builds a `Watcher`: two properties, one a `weak var` and the other an `unowned let`, point to the same `Target` instance. While the instance is alive both are read; then the instance is released and only the weak property is read. The unowned property is not read after this point; the read would stop the program.

```swift
// main.swift — a weak and an unowned view of the same target
final class Target {
    let name: String
    let owner: Probe

    init(_ name: String, owner: Probe) {
        self.name = name
        self.owner = owner
    }

    deinit {
        print("deinit target \(name)")
        _ = owner.eval(name)
    }
}

final class Watcher {
    weak var soft: Target?
    unowned let strict: Target

    init(_ target: Target) {
        soft = target
        strict = target
    }
}

let looked = Probe("weak-and-unowned")
for round in 1...2 {
    var target: Target? = Target("target-\(round)", owner: looked)
    let watcher = Watcher(target!)
    print("while alive: weak \(watcher.soft?.name ?? "nil"), unowned \(watcher.strict.name)")
    _ = looked.use { target = nil }
    print("after gone: weak \(watcher.soft?.name ?? "nil")")
}

looked.report()
```

```
while alive: weak target-1, unowned target-1
deinit target target-1
after gone: weak nil
while alive: weak target-2, unowned target-2
deinit target target-2
after gone: weak nil
weak-and-unowned: 2 evaluations, 2 uses -> on-every-use
```

While the instance is alive, both reads give `target-1`; at this moment the two forms cannot be told apart. After the line `deinit target target-1`, the weak read gives `nil`: once the instance is destroyed, a weak reference reads as `nil`. The unowned read is not measured at the same point: the `strict.name` line would read an instance that is gone, and the runtime would stop the program. The choice between the two forms is therefore not a choice of reading style but a promise about what must hold. If the target can go before the `watcher`, write weak; if that is impossible, write unowned. `weak-and-unowned` counts two evaluations in two rounds and says `on-every-use`; the result of the weak read is determined anew at every read. The result of an earlier read is not carried to a later one.

## The Bounding Measurement

Weak and unowned references have only this in common: they do not hold what they point to. They part ways when read after the instance they point to is gone. A weak reference gives `nil`, and the second measurement above showed this. An unowned reference has no such guarantee: reaching an instance that is gone through `unowned` stops the program at run time. This is why that read is not measured. The fragment below is source only and is not run. It makes no output claim either.

```swift
// Source fragment: not run
var customer = Customer("customer-3", owner: bound)
let card = Card("card-3", customer: customer, owner: bound)
customer = Customer("customer-4", owner: bound)
print(card.customer.name)
```

The third line releases the last strong reference to `customer-3`; because `Card` does not hold it, the instance is destroyed. The fourth line reads an instance that has been destroyed. Had the same structure been written with `weak`, the read would have given `nil` and the program would have continued. The choice is therefore a lifetime promise: `unowned` is bound only to an instance that is certain to live longer than the instance carrying the reference; wherever there is doubt, `weak` is used. The compiler does not check this promise, so this is a limit, not a moment.

**MA2.** One class pair was measured for each linking form; all three pairs are small chains of two classes. That the same rule holds in longer cycles (three or more classes) was not shown in this lesson. Choosing the pairs is a design choice.

## Summary

- If two classes hold each other strongly, their reference counts never drop to zero and neither `deinit` runs; this is a retain cycle.
- Making one side `weak var` breaks the cycle; a weak reference becomes `nil` when the instance it points to is destroyed.
- `unowned let` is bound to the side that lives longer and never becomes `nil`; reading an instance that has been destroyed stops the program, so it is not measured.
- This lesson's moment: **never**. In a retain cycle the `deinit` body is not evaluated at any moment; once the cycle is broken it runs in every round.

## Next Step

In this lesson the cycle was built between two class properties. A closure stored in a class's own property can build the same cycle by capturing `self` strongly, and this is the most common form of retain cycle. The next lesson measures capturing in closures and when the `[weak self]` capture list is evaluated.
