iOS

June 3, 2019

Swift retain cycles

In many higher level programming languages there exists garbage collection, which turns memory management into a long forgotten issue.

Swift doesn’t have garbage collection. Instead it has something called Automatic Reference Counting (ARC). It works, like the name suggests, by counting the number of strong and weak references an object has. As long as an object has one or more strong references pointing to it it will not be freed from memory. But as soon as an object has zero strong references it will be freed.

Problem arises when two objects has strong references to each other. Then consider the following scenario.

Imagine that you have the following class

1
2
3
4
5
6
class TodoList {
    var delegate: TodoListDelegate?
    var items: [ListItem]?

    ... the rest of the class
}

The Todo-list has a delegate that is in charge of how to handle certain events, like when an item is selected. When an item is selected we want to do something with the TodoList object, perhaps highlight the selected element.

1
2
3
4
5
6
7
class TodoListDelegate {
    var todoList: TodoList?

    func didSelect(item: ListItem) {
        // Do something with the ToDo list
    }
}

In the ViewController we put them together and set them up.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ViewController: UIViewController {
    var todoList: TodoList?

    override func viewDidLoad() {
        todoList = TodoList()
        let delegate = TodoListDelegate()
        delegate.todoList = todoList
        todoList.delegate = delegate
    }

    override func viewWillDisapear() {
        todoList = nil
    }
}

Now, the TodoList and its delegate has references to each other. So even after the ViewController is deallocated they will still take up memory, thus we have a memory leak.

The solution

Fixing this is fairly easy. Declare the TodoList inside the delegate as weak like this.

1
2
class TodoListDelegate {
    weak var todoList: TodoList?

That will mean we only get one strong reference between the objects and they can be deallocated.

It is also possible to use ‘unowned’ which, similar to ‘weak’, isn’t creating a strong reference. The difference is that weak only works with optionals, thus allows the variable to be nil. An ‘unowned’ variable must have a value. If it is deallocated and then used, the application will crash.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *