Select Page

Strong reference cycles can cripple your application. In this article, I show you how to resolve the strong reference cycles we created in the previous installment of this series.

Turning Strong References Into Weak References

You may already have an idea how we can break a strong reference cycle. That’s right. We can break strong reference cycles by getting rid of strong references. Simple. Right? We won’t be getting rid of every strong reference, though. We only need to replace one strong reference to break the strong reference cycle.

But we need a replacement for the strong references we remove. The view controller and the table view we encountered in the previous article still need to know about each another. They need to keep a reference to one another in order for them to communicate.

By replacing a strong reference with a weak reference, we meet both requirements. We can remove a strong reference to break the strong reference cycle and, at the same time, we preserve the relationships between the objects that make the application tick.

What Is a Weak Reference

Weak references are similar to strong references. A weak reference also points to a class instance. The key difference is that a weak reference doesn’t prevent a class instance from being deallocated. In other words, a weak reference is ideal to replace a strong reference to break a strong reference cycle. Take a look at this diagram to better understand the solution.

What Is a Weak Reference
What Is a Weak Reference

Remember from the previous article, a view controller holds a strong reference to its table view. If a table view also holds a strong reference to its delegate, we end up with a strong reference cycle. We can break the strong reference cycle by turning the table view’s delegate into a weak reference.

When the view controller is deallocated, the table view it references is also deallocated. The weak reference of the table view’s delegate doesn’t keep the view controller alive. The memory leak we created in the previous article is resolved by turning a strong reference into a weak reference.

And that is how the UITableView class is implemented by the UIKit framework. I can prove this by showing you the declaration of the UITableView class. The delegate property of the UITableView class is a variable property of type UITableViewDelegate?. The weak keyword prefixing the property declaration indicates the property holds a weak reference to the class instance it points to.

UITableView Class Declaration
UITableView Class Declaration

How to Use a Weak Reference

The declaration of the UITableView class shows us how to declare a property as weak. We simply prefix the property declaration with the weak keyword. But there are several details that aren’t immediately obvious.

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’s 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 always needs to be an optional type. When the class instance the weak reference points to is deallocated, ARC automatically sets the weak reference to nil. This is a safety mechanism to prevent access to a class instance that no longer exists.

But there’s another requirement. Because ARC needs to be able to set a weak reference to nil when the class instance it points to is deallocated, a weak reference needs to be 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?, an optional type.

open class UITableView : UIScrollView, NSCoding {
    
    ...

    weak open var delegate: UITableViewDelegate?

    ...

}

Breaking Another Strong Reference Cycle

In the previous article, we created another strong reference cycle. Remember the example in which we defined the Account and Plan classes.

class Account {

    // MARK: - Properties

    var plan: Plan

    ...

}

class Plan {

    // MARK: - Properties

    var account: Account

    // MARK: - Initialization

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

To break the strong reference cycle between Account and Plan, we could mark the account property of the Plan class as weak. But this also means we need to declare the account property as Account?, 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
    }
    
}

While this isn’t the end of the world, it is inconvenient since we know that every Plan instance is guaranteed to have an Account instance associated with it. We can resolve this inconvenience by telling the compiler the account property is an unowned reference.

The solution is simple. We replace the weak keyword with the unowned keyword. There’s no longer a need to declare the account property as an optional type.

class Account {

    // MARK: - Properties

    var plan: Plan!

    ...

}

class Plan {

    // MARK: - Properties

    unowned var account: Account

    // MARK: - Initialization

    init(account: Account) {
        self.account = account
    }
    
}
You can use an unowned reference to break a strong reference cycle.
You can use an unowned reference to break a strong reference cycle.

What Is the Difference Between Weak and Unowned References

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

Questions? Leave them in the comments below or reach out to me on Twitter.

<< What Are Strong Reference CyclesWhat Is the Difference Between Strong, Weak, and Unowned References >>