Automatic Reference Counting, or ARC for short, was introduced in Objective-C several years ago. It greatly simplifies memory management in Swift and Objective-C. Automatic Reference Counting usually works without you having to do anything. But there are scenarios in which ARC needs a little bit of help.

To avoid strong reference cycles, you sometimes need to give the compiler a hand. Unfortunately, this trips up many developers, especially those that don't have experience with Objective-C. Weak and unowned references in particular often cause confusion. That is the focus of this article.

What Are Weak and Unowned References

A reference to an instance is strong by default. But that is not always what you want. If a strong reference is not appropriate, you have a few other options, weak and unowned references.

Weak References

As the name suggests, a weak reference keeps a weak reference to the instance it references. This means that the reference to the instance is not taken into account by ARC. Remember that an instance is deallocated if no other objects have a strong reference to the instance.

Remember that an instance is deallocated if no other objects have a strong reference to the instance.

Unowned References

Unowned references are similar to weak references in that they don't keep a strong reference to the instance they are referencing. They serve the same purpose as weak references, that is, they avoid strong reference cycles.

But there are several key differences between weak and unowned references that are important to understand.

What Are the Differences

The first difference you need to know about is that an unowned reference is always expected to have a value. This is not true for weak references, which are set to nil if the instance they reference is deallocated. When that happens, the reference is set to nil.

Because a weak reference can be set to nil, it is always declared as an optional. That is the second difference between weak and unowned references. The value of a weak reference needs to be unwrapped before it can be accessed whereas you can directly access the value of an unowned reference.

Be careful, though. If the referenced instance of an unowned reference is deallocated, it isn't set to nil. As a result, a fatal error is thrown if the referenced object of the unowned reference is accessed.

A Few Examples

Weak and unowned references are best understood with a few examples. Let me start with an example of a weak reference.

Delegation

Chances are that you are familiar with the delegation pattern. You probably know that the UITableView class defines a delegate property. Among other things, the delegate is responsible for responding to user interaction. For example, the table view notifies its delegate when the user taps one of its rows.

The table view doesn't keep a strong reference to its delegate. Why is that? If the table view would keep a strong reference to its delegate, the delegate would only be deallocated when the table view is deallocated and that is not what you want.

Assume for a moment that the table view is owned by a view controller and the view controller also acts as the delegate of the table view. That is a very common scenario. In that scenario, the view controller would never be deallocated if the delegate property of the UITableView class would be declared as strong. Take a look at this diagram to better understand the problem.

A Strong Reference Cycle in Swift

If you don't believe me, then I suggest you take a look at the public interface of the UITableView class. The delegate and the dataSource properties are declared as weak properties.

open class UITableView : UIScrollView, NSCoding {

    ...

    weak open var dataSource: UITableViewDataSource?
    weak open var delegate: UITableViewDelegate?

    ...

}

The strong reference cycle is broken by declaring the property as weak.

Breaking A Strong Reference Cycle

Accounts and Pricing Plans

The example I usually use to explain unowned references is that of accounts and pricing plans. If you sign up for Netflix, you choose a pricing plan. You create an account and you choose the pricing plan that fits your needs. This is what that could look like in code.

class Account {

    // MARK: - Properties

    var plan: Plan

}

class Plan {

    // MARK: - Properties

    var account: Account

    // MARK: - Initialization

    init(account: Account) {
        self.account = account
    }

}

This doesn't look right. Take a look at the following diagram to better understand the problem.

Another Strong Reference Cycle

In the example, we created a strong reference cycle. An account instance keeps a strong reference to a plan and the plan of the account keeps a strong reference to the account it is linked to. Remember that properties are by default strong.

We can break the strong reference cycle by marking the account property of the Plan class as unowned.

class Account {

    // MARK: - Properties

    var plan: Plan

}

class Plan {

    // MARK: - Properties

    unowned var account: Account

    // MARK: - Initialization

    init(account: Account) {
        self.account = account
    }

}

The resulting diagram looks much better.

Breaking Another Strong Reference Cycle

It is important to understand why we marked the account property as unowned instead of weak. An account should always have a plan associated with it and a plan shouldn't exist without an account.

Remember what I wrote earlier. An unowned reference is always expected to have a value. When the Account instance is deallocated, the Plan instance it is linked to is also deallocated. This is only possible because the account property is marked as unowned instead of strong, which is the default for properties.

Managing Memory

It is important to understand the basics of memory management to avoid strong reference cycles. Even though the compiler takes care of many of the details of memory management for you, you always need to be careful when working with reference types.