Avoiding reference cycles

When an object contains references to other objects, you should always be careful to avoid situations where both objects continuously hold a reference to each other. For example, a relationship between a table view and its delegate or data source could become a reference cycle if the relationship isn't managed properly. Objects can only be deallocated and the memory they use can only be freed if there are no objects referencing them anymore:

The preceding figure illustrates this. The view controller holds onto to the tableView and the tableView holds on to its delegate, which is the view controller. This means that neither object can ever be deallocated because for both the view controller and the tableView there is always at least one object referencing each at any given time. Of course, Apple has made sure that this doesn't occur in your apps by making sure that a tableView does not hold on to its delegate forever. You'll see how in just a second.

Another situation where a reference cycle could be created is in a closure. When you implicitly reference self in a closure, the compiler complains that you must explicitly refer to self. Doing this creates a reference to self inside of the closure, potentially resulting in a reference cycle. Throughout this book, you've seen a bunch of closures and we've always used a capture list when we referred to self inside of the closure:

api.fetchData { [weak self] 
    self?.tableView.reloadData()
}

The preceding example shows an example of using a capture list, it's the part right before the in a keyword. The list captures a weak reference to self, which means that we don't create a reference cycle between the closure and self. If our api object somehow stores the closure in a variable and we haven't used a weak reference to self, we potentially have a reference cycle. If the api object itself is held onto by another object, we can be pretty sure that a reference cycle is created.

Making the reference weak tells the app that the reference to self does not add up to the reference count of self. This means that if there are only weak references left to an object, it's OK to deallocate it and free the memory. Memory management, and more specifically reference counts, isn't a simple subject. One way to think about this subject is that your app has an internal count of the number of objects that point to another object. For instance, if you create an instance of a UIView inside of a UIViewController, the reference count for the UIView is one. When the UIViewController is deallocated, the reference count for the UIView is zero, meaning that it can be deallocated safely.

If the UIView has a reference to the UIViewController as well, both objects will keep each other around because the reference count for each instance won't ever reach zero. This is called a reference cycle. This cycle can be resolved by making at least one of the references involved a weak reference. Since weak references don't contribute to the reference count, they prevent reference cycles from happening. This is how Apple has made sure that a tableView does not create a reference cycle with its delegate or data source; the references are marked as weak.

As an alternative to making a reference weak, you can also mark it as unowned. While weak is essentially a safe optional value, unowned makes the object implicitly unwrapped. It's often best to take the safe route and mark a captured reference as weak because your app won't crash if the weak referenced instance has been deallocated somehow, while it would crash if the reference is unowned.

Reference cycles aren't easy to grasp, especially if you consider weak references and reference counting. It's really easy to find yourself confused and frustrated. Luckily, the Instrumental app contains a couple of issues with references and retain cycles, so we can try and understand them better by discovering them in our app.