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 correctly. Objects can only be deallocated if no objects are referencing them anymore:

The preceding figure illustrates this. The view controller holds onto tableView and tableView holds onto its delegate, which is the view controller. This means that neither object can ever be deallocated because for both the view controller and 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 tableView does not hold onto 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 they always used a capture list self was used inside of the closure:

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

The preceding example shows an example of using a capture list. The capture list is the part right before the in keyword. The list captures a weak reference to self, which means that no reference cycle is created between the closure and self. If the api object stores the closure in a variable and you didn't use a weak reference to self, you might have a reference cycle. If the api object itself is held onto by another object, you 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 reference counts aren't simple. 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 UIView inside of UIViewController, the reference count for UIView is one. When UIViewController is deallocated, the reference count for UIView becomes zero because the view controller doesn't use it anymore, meaning that it can be deallocated safely.

If UIView has a reference to 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 broken by marking at least one of the references as 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 tableView does not create a reference cycle with its delegate or data source; the references to these objects are marked as weak.

As an alternative to making a reference weak, you can 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 understand, especially if you take into account weak references and reference-counting. It's really easy to get confused about this topic. Luckily, the Mosaic app contains a couple of issues with references and retain cycles so you can immediately put your newly acquired knowledge to the test.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset