When to use strong, weak and unowned reference types in Swift and why

Posted by Oleksandr Kruk

We have been using Swift at Funding Circle for a couple of years now.
One particular subject that was interesting to get to the bottom of was the usage of weak vs unowned
reference types. Why are there three ways (strong, weak, unowned) of referencing an object and when should we use each.

First lets understand why is the reference counting important. Swift does its memory management by relying
on the ARC. As name implies, it counts references in order to understand
if an object has to be kept in memory or not. That’s an extremely simplified explanation, to learn more
please refer to Apple’s ARC documentation1.

Before we start lets make sure our communication is clear. When talking about variables, we are referring
to the Swift reference types (class and function). Reference counting does not work the same way for value types (struct, enum and basic types). Swift does a copy on write
whenever a value type is being changed. This means that, in general, we can assume that in practice a value type
has a reference count of at most 1. In reality the values also point to one same instance up to the point when
one of the values is being changed, only at that point a copy of the original value will be done, then changed
and persisted in its own allocated memory.

Strong references

This is the default reference type in Swift. Whenever we declare a variable without
specifying its reference type, it will always be strong. A reference being strong means that the ARC
will increment the reference count for the object being referenced by a variable.
This impacts memory management since an object’s memory can not be released while the reference count
is greater than zero.

Although in real world Balance entity would be a great candidate for being a struct, we made it a class
for demonstration purposes.
So we have two entities, Balance and Lender. Lender’s property availableFunds holds a strong reference to
an object of type Balance. At the point when we assign the Balance object to a named variable,
the object’s reference count is incremented by one. This means that there is one more variable pointing to the
memory that was allocated for that object. The implication of this assignment is that the Balance object
can not be deallocated while the Lender instance exists.

...self.availableFunds=availableFunds// reference count += 1...

An important note about this example is that in Swift the arguments are constants by default and can not be
changed. This means that when we assign the argument to the property, a copy of the argument will be made when it’s
being changed.

Multiple variables pointing to the same object increment it’s reference counting as we can see in this snippet:

A constant will have always a strong reference type, so when we declare let balanceConstant it will
increment the reference counting of the Balance object in memory. Whenever a variable that points to an object
which is as well referenced by a constant is changed, a copy of the object will be made and that copy is
the one being updated.

Weak reference

Contrary to strong reference, weak reference has no impact on an object’s reference count. Meaning that if
we declare a weak variable pointing to an object, that object’s reference count will remain the same as it
was before. Lets see what that means in practice with the following simple example:

We start by creating a balance variable that will hold a strong reference to the newly created Balance
object. This increments the object’s reference count and makes it equal to one.
Next we declare a weak variable balanceCopy which will not change the object’s reference count.
We then remove the strong reference from the object by assigning nil to the balance variable that was holding strong reference
to the Balance object. This brings the reference count to zero and consequently deallocates the object
which means that our weak balanceCopy variable will have no object to point to and thus when we
try to unwrap it, the result is nil.

Unowned reference

Similarly to weak reference, an unowned reference does not increment the object’s reference count. But there
are several important differences in its usage.
One of the differences between weak and unowned is the fact that Swift runtime keeps a secondary reference
count for unowned references. When the strong references count goes to zero, the object will release all the
references it has but the object’s own memory won’t be released while there are unowned references pointing to it.
The object’s memory is marked as zombie though. It means that the user can not rely on whatever is stored in that memory
and accessing it, without a safe unwrap, will crash the program. The check of the reference happens at runtime, that’s why accessing it is a runtime error.
Another difference is that unowned variables can not be of optional type. This is very important given that Swift will force us to use the variable without being able to double check if it’s pointing to a valid object.
Lets look at the following example:

To start with, we declare an optional balance variable that holds a strong reference to Balance object.
In the next line we declare an unowned variable balanceCopy, which will point to the same Balance object
as the balance variable but will not change the object’s reference count.
When we then assign nil to the balance variable, the Balance object is marked as zombie, so its
memory is not accessible and thus when we try to get the amount on balanceCopy we get a runtime error.

When to use a strong reference

This one is simple, given the examples that we have seen. It becomes clear that we should use a strong reference whenever we want to guarantee that we are always able to access the variable. This is specially true for things like object properties which should always exist during their owner’s lifetime. To reiterate, in our case, when we
have a Lender object we know he will definitely have a name and will have a balance, even if he has just
created his account with £0.00. For more detailed examples check Apple’s examples1.

So when strong reference is not advised

The situation becomes more complicated when we start having bidirectional references between objects.
Such references are common in delegate pattern as we can see in the following example that uses
the LenderDepositDelegate to define a deposit operation.

Usually in this case the view receives some input event from the user and delegates the handling of that event to the controller (which is also the delegate in our case), and for doing that the view has a reference to the controller.
The problem is that the controller also has a reference to the view (otherwise the view would be immediately
deallocated after being initialized because its reference count would be zero). This creates a reference cycle as you can see in the diagram below.
It clearly depicts a situation where, when strong reference is used, neither of the objects can be
deallocated because they always have at least one other object pointing to them.

So it’s good practice in delegate pattern to never strongly reference the delegate, as we can see in the snippet
below.

By doing so, we break the reference cycle and allow for the AvailableFundsViewController to be deallocated
when it’s no longer in use (e.g.: we navigate to a different controller). And that in turn leaves the AvailableFundsView with reference count zero and consequently makes it possible for the view to be deallocated
as depicted in the following diagram.
This is a very simple case though, in the real world things are much more complex to analyse, but this
should be enough to understand the general idea behind it.

When to prefer weak over unowned

As we have seen, there is no practical difference between weak and unowned in terms of the reference count
of an object. The difference between the two lies in the mechanism that the Swift language uses to handle them.
When we use the weak reference, Swift explicitly makes the variable an optional and doesn’t let us
use it unless we unwrap it. This creates a mandatory compile
time verification of the reference, meaning that we will not be allowed to use it without checking it first.
This obviously can be defeated by using force unwrap !, which is generally discouraged unless we have
some kind of guarantee that the variable is pointing to a valid object.
In case of unowned reference, it is implicitly unwrapped, meaning that the reference will only be
verified at runtime, which leads to a runtime crash if the reference points to deallocated object.
This mechanism makes the weak reference type the safe choice if we don’t want to have surprises
when our program is running.

So when should we use unowned? The rule here is to use it iff we can guarantee that the lifecycle
of the referenced object is equal or greater than the lifetime of the variable pointing to it. In that case
we know for sure that the object will not be deallocated and we can safely use it.
Let’s adapt our previous example in order to demonstrate a possible usage of unowned property.

In the example above it’s safe to declare balance owner Lender as unowned because we know that Lender will
always exist while Balance exists. In case lender is deallocated, the Balance gets deallocated as well.
This means it’s safe to use unowned since the Lender will always exist during the lifetime of Balance object.

Although the unowned reference has a slight performance benefit over weak reference, it’s not
significant for most of the projects out there.
In real scenarios it is very hard to guarantee the pre-condition of the referenced object being always available during
the lifecycle of the variable that is pointing to it, unless the relation between the entities is such that it
guarantees this condition1. And even when it’s theoretically easy to prove such conditions,
nothing prevents somebody from changing the code in a way that that condition does not hold anymore and
we unintentionally have a runtime crash.

Recap

We have seen that strong, weak and unowned each have their own clear use cases. The strong reference is useful
for declaring the attributes of an entity. The weak reference is a safe way to break reference cycles. As for unowned, it has a very specific use case, for when we know that the pointee’s lifecycle is at least as long
as the pointer’s lifecycle. In real world though, we are always at risk of our assumptions being changed
and no longer hold, leading our once safe code to a runtime crash. For this reason, weak reference is always
safer to use than unowned.

Resources

Apple provides a guide with examples of when each reference type makes sense and how to break reference
cycles1