Unit Testing Memory Leaks In iOS With Swift

Darren Findlay
3 min readNov 25, 2021

--

Memory leaks are a common source of bugs in our code and can be difficult to track down. Let's have a look at how we can detect memory leaks in our tests.

What is a memory leak?

A memory leak occurs when some allocated space in memory cannot be freed up due to a retain cycle. Swift and Objective-C use automatic reference counting to manage memory. A retain cycle is created when two or more objects hold strong references to each other like so:

foo retains bar, bar retains foo.

Example:

Let’s look at a simple example. We have two requirements:

  • When the view loads, render the supplied title.
  • When the view loads, render the supplied subtitle.

Here’s our implementation:

We’ll add some tests to verify the behaviour:

Let’s run the tests:

Passing! 🥳

But theres a problem… We have a retain cycle.

With the MVP (Model View Presenter) pattern, there is bidirectional communication between the view and presenter. Typically the view owns the presenter and the presenter has a weak reference to the view. Lets see if we can make our tests fail if we forget to weakify the reference to the view. We’ll start with the “test_rendersTitle” test.

The addTearDown function enables us to pass a closure thats invoked after the test function returns, so in our case if there are no memory leaks, both the view controller and presenter should have been deallocated and should be nil. Let’s run it and see:

Great! We now have a failing test. Lets make it pass by adding a weak reference to the view from the presenter.

Run the tests:

And we’re green again 🎉

This is something we’re going to want in most of our tests, so lets see if we can generalise our approach so we aren’t repeating ourselves and making our tests harder to read. we’ll start by extracting a custom assertion:

We’ll use this in our tests:

Much better, now we can detect memory leaks in our tests. We have some repetition though. Every time we create our object graph we track memory leaks for each object created. We can extract out another helper function that creates our subject under test and tracks memory leaks:

Beautiful 😍 Our tests are more readable and now we’re detecting memory leaks.

--

--