Understanding Swift Memory Management

How to Break a Strong Reference Cycle

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy

Strong reference cycles negatively impact your application's performance. They lead to memory leaks and unexpected behavior that is often hard to debug. In this episode, I show you how to resolve the strong reference cycles we created in the previous episode of this series.

Turning Strong References Into Weak References

If you paid attention in the previous episode, then you may already know how to break a strong reference cycle. The solution is straightforward. We can break a strong reference cycle by using references that are not strong. That makes sense. Right?

This brings up the question "What do we replace the strong references with?" In the previous episode, we discussed the relationship between a view controller and its table view. The view controller still needs a reference to its table view and the table view needs a reference to its delegate, the view controller in the example. How do we resolve this problem?

By replacing a strong reference with a weak reference, the relationship between the objects remains intact and the strong reference cycle is broken. That is the solution we need.

What Is a Weak Reference?

A weak reference is similar to a strong reference. It too points to a class instance. The difference is that a weak reference doesn't prevent a class instance from being deallocated. This means that a weak reference can be used to break a strong reference cycle. Take a look at this diagram to better understand the solution.

What Is a Weak Reference

Remember from the previous episode, a view controller holds a strong reference to its table view. If a table view also holds a strong reference to its delegate, the view controller in the example, we end up with a strong reference cycle. If the table view keeps a weak reference to its delegate, then the strong reference cycle is broken.

If the view controller is deallocated, then the table view it references is also deallocated. Because the table view keeps a weak reference to its delegate, the view controller in the example, the table view doesn't prevent the view controller from being deallocated. The memory leak we created in the previous episode is resolved by replacing a strong reference with a weak reference.

The UIKit framework uses this pattern for the UITableView class. We can verify this by inspecting its interface. Press Command and click the UITableView symbol in ViewController.swift. This takes us to the interface of the UITableView class.

@available(iOS 2.0, *)
open class UITableView : UIScrollView, NSCoding, UIDataSourceTranslating {


    public init(frame: CGRect, style: UITableView.Style) // must specify style at creation. -initWithFrame: calls this with UITableViewStylePlain

    public init?(coder: NSCoder)


    open var style: UITableView.Style { get }


    weak open var dataSource: UITableViewDataSource?

    weak open var delegate: UITableViewDelegate?

    ...

}

The delegate property of the UITableView class is a variable property of type UITableViewDelegate?. The weak keyword prefixing the property declaration indicates that the property holds a weak reference to the class instance it points to. The same is true for the dataSource property of the UITableView class.

How to Use a Weak Reference?

The interface of the UITableView class illustrates how to use a weak reference. The delegate and dataSource properties are declared weakly by prefixing the property declaration with the weak keyword. There are a few subtle details you need to be aware of, though.

When the class instance the property or variable points to is deallocated, the weak reference no longer points to a class instance. Unlike a strong reference, it cannot prevent the class instance from being deallocated. In other words, it is possible that a weak property or a weak variable doesn't point to a class instance. A weak reference is not guaranteed to always have a value.

A weak reference is not guaranteed to always have a value.

For that reason, a weak reference is always of an optional type. If the class instance the weak reference points to is deallocated, then the weak reference is automatically set to nil. This is a safety mechanism to prevent access to a class instance that may no longer exist.

There is another requirement you need to be aware of. Because Automatic Reference Counting needs to be able to set a weak reference to nil when the class instance it points to is deallocated, a weak reference is always declared as a variable.

The declaration of the UITableView class confirms this. The delegate property is a variable property and it is of type UITableViewDelegate?.

@available(iOS 2.0, *)
open class UITableView : UIScrollView, NSCoding, UIDataSourceTranslating {


    public init(frame: CGRect, style: UITableView.Style) // must specify style at creation. -initWithFrame: calls this with UITableViewStylePlain

    public init?(coder: NSCoder)


    open var style: UITableView.Style { get }


    weak open var dataSource: UITableViewDataSource?

    weak open var delegate: UITableViewDelegate?

    ...
}

Breaking a Strong Reference Cycle

In the previous episode, we discussed the relationship between accounts and plans. An account has a reference to a plan and a plan has a reference to an account. The account and the plan depend on one another.

Breaking a Strong Reference Cycle

Let's translate that example to code. The Account class defines a variable property, plan. The plan property is an implicitly unwrapped optional. The Plan class defines a constant property, account, of type Account. It also defines an initializer that accepts an Account instance.

class Account {

    // MARK: - Properties

    var plan: Plan!

}

class Plan {

    // MARK: - Properties

    let account: Account

    // MARK: - Initialization

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

}

To break the strong reference cycle between an Account instance and a Plan instance, we declare the account property of the Plan class as weak. Remember that this has a few consequences. We need to declare the account property as a variable property and it needs to be of an optional type.

class Account {

    // MARK: - Properties

    var plan: Plan!

}

class Plan {

    // MARK: - Properties

    weak var account: Account?

    // MARK: - Initialization

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

}

Defining the account property as an optional is fine, but it is inconvenient. We know that every Plan instance is guaranteed to have an Account instance associated with it. We can work around this inconvenience by replacing the weak keyword with the unowned keyword. This turns the weak reference into an unowned reference. We discuss unowned references in detail in the next episode.

class Account {

    // MARK: - Properties

    var plan: Plan!

}

class Plan {

    // MARK: - Properties

    unowned var account: Account

    // MARK: - Initialization

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

}

Once a plan is associated with an account, the account the plan references shouldn't change. This is easy to implement by declaring the setter of the account property as private. This is a subtle but important detail.

class Account {

    // MARK: - Properties

    var plan: Plan!

}

class Plan {

    // MARK: - Properties

    private(set) unowned var account: Account

    // MARK: - Initialization

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

}

Breaking a Strong Reference Cycle

Mind the Exclamation Mark

The previous example comes with a warning. The Account class declares the plan property as an implicitly unwrapped optional. In Swift, an exclamation mark communicates potential danger. I have declared the plan property as an implicitly unwrapped optional for convenience, but it isn't something I recommend. I go into detail about this topic in When Should You Use Implicitly Unwrapped Optionals.

What Is the Difference Between Weak and Unowned References

Unowned references also come with a warning. An unowned reference is very similar to a weak reference. It weakly references the class instance it points to and, like a weak reference, it can be equal to nil. If an object accesses an unowned reference that is equal to nil, then a fatal error is thrown and your application crashes. This is similar to accessing an implicitly unwrapped optional that is equal to nil.

In the next episode of Understanding Swift Memory Management, we take a closer look at the differences between weak and unowned references. The differences are subtle but profound.

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy
Next Episode "What Is the Difference Between Strong, Weak, and Unowned References"