Memory management is one of those topics that seems to take a back seat to most other priorities. While each of us knows we should be doing something to make sure our apps aren’t using more memory than they should, we often find ourselves just magically trusting that automatic reference counting (ARC) will do its job even when we don’t do ours. Most of us shrug our shoulders and say, “Weak vs. Unowned References? Eh, what’s the difference?” It’s my hope that by clearing up this mystery, we’ll no longer regard Swift’s memory management system as some magical black box that “just works.” We’ll understand it and apply our knowledge to build better apps.

How does memory management work?

Everything in your app needs memory. Classes, structs, integers, enums, they all need some place to live. While one of these entities is in use, it resides in memory. Once your app has stopped using that entity, it should be cleared from memory. There are limitations on the device. There can only be so much space in memory for so many things, and every app is competing with other apps for that space. If an app uses more memory than the system gives it, the app will either slow down or come to a screeching halt, so memory needs to be frequently cleared.

For the most part, you don’t need to worry about memory management in Swift. ARC handles it for you. Usually just setting an entity to nil will cause the operating system to clear that entity out of memory.

But there are situations where the structure of your code can put roadblocks in front of the operating system, effectively preventing class instances from getting cleared out of memory when they should be. The most common of these is known as a reference cycle. Reference cycles happen when the memory management system wants to clear out a variable but something else needs it, so it can’t. If two entities both need each other, neither of them ever gets cleared from memory, and you get what is known as a memory leak (a piece of memory that can’t get reused because its data will never get cleared).

A reference cycle is kind of like the relationship between a parent and a child. Both are strongly attached to one another. Louis C.K. Once joked that as a dad, he doesn’t even get to die. Strong reference cycles work that way too.

As an example, let’s define a class that leaves open the possibility of creating a strong reference cycle.

Simply creating an instance of both a parent and its child isn’t enough to create a strong reference cycle. We need to hook them up to one another, so let’s do that.

This is a strong reference cycle. If you try to set deborah = nil, she won’t get deallocated because deborahJR needs her. If you set deborahJR to nil, she also won’t get deallocated because deborah needs her.

I say “needs,” but the underlying mechanism is more complicated than that. ARC is responsible for the memory cleanup, and ARC only cleans up a reference when nothing else refers to that entity (its reference count is zero). That is what reference counting is all about. Each time a reference to an instance of a class is created, that instance’s reference count goes up by one, and every time a reference is removed, the reference count goes down by one. When an instance has a reference count of zero, ARC can safely remove it from memory.

So now you can see how neither parent nor child can get removed from memory. The parent’s reference count will never get to zero because its reference to child can’t get removed until it itself gets removed. It’s a circular kind of reasoning that leads to both entities staying in memory forever.

Weak and Unowned references are a tool for breaking the circle and allowing one entity to get deallocated from memory. This in turn makes it possible for the other entity to get deallocated.

Weak references to the rescue!

We might reimagine the same scenario, but this time we’ll work with Kryptonians instead of children. Superman, for the most part, is independent of his parents. If they die, his super powers will protect him from the hazards of the universe. We could model it like this.

Although we have linked the two entities in a similar way, we have not created a strong reference cycle. Because Superman’s reference to his parents is weak, we can set them to nil when the planet Krypton is destroyed, and ARC will clear them from memory because their reference count is zero. A weak reference is a way of creating a reference to something without increasing the reference count for that thing.

In Swift, all weak references need to refer to optional types. They are used in situations where the entity referred to can be optional. Superman’s parents could be dead (hence inaccessible as a property), so they are declared as an optional weak reference.

There are situations where a weak reference isn’t appropriate because the thing being referred to must not be nil. In those situations, it is best to use “unowned” to denote the reference type.

A good example would be Superman’s superpowers. The superpowers are nothing without Superman to control them, and when Superman dies from Kryptonite exposure, the superpowers die with him.

We could model it like this:

This sets up an interdependency between any given Kryptonian and her superpowers. The superpowers variable on Kryptonian is declared as an implicitly unwrapped optional in order to bypass one of Swift’s requirements that an initializer cannot pass self to another initializer until all properties on the instance have been set (also known as two phase initialization). Because all of the properties on Kryptonian are either optional or implicitly unwrapped optional, they are already set when the init() method gets called, which makes self available to the Superpowers initializer.

With this setup, one need only create an instance of a Kryptonian to access the superpowers linked to him. Those superpowers also store a reference to the Kryptonian that owns them, giving us another means of access to our Kryptonian without creating a strong reference cycle. If the instance of that Kryptonian is set to nil, that Kryptonian will be removed from memory along with his superpowers just as one would expect. Superpowers need a person to command them if they are to be of any use at all.

There are other scenarios where strong reference cycles can result, and I’ve really only covered two possible solutions to strong reference cycles. Hopefully this eliminates some of the confusion surrounding weak references and unowned references. Depending on your project, you may need to use one, both, or none at all. Even if this doesn’t affect any of your current projects, you can at least sleep a little better understanding how ARC clears out memory.