ARC, also know as Automatic Reference Counting, used to manage your app’s memory by keeping counts of all the allocated class instances and freeing up any allocated memory when those instances are no longer needed. Before we dive into ARC lets quickly discuss value types and reference types a they are an integral part to memory management.

Value Types

If you worked with Swift you should be able to distinguish value types with reference type. Struct and Enums are value types. Let’s see and example.

You maybe surprised to see the above result because the changing the value of myAge did not change the value of yourAge which resulted in both properties being not equal. This is true because when you assign myAge to yourAge the value is copied rather than referenced.

Reference Types

Lets look at a reference type example

As you can see because AgeClass is a class type the myAge instance was passes by reference, so when we assigned myAge to yourAge, the value stored in myAge was not copied. Instead, the reference was assigned to yourAge. This means both myAge and yourAge are pointing to the same reference in memory.

ARC

Now that we know the differences of both value and reference types it’s important to understand that when it comes to memory management for value types, the compiler is good at disposing instances of structs and enums when they are no longer needed. However for reference types, it’s difficult for the compiler to know and understand when it’s safe to deallocate a class instance. This is where ARC comes in.

Every time you create a new instance of a class type, ARC allocates a chunk of memory to store information about that instance. This memory holds information about the type of the instance, together with the values of any stored properties associated with that instance. When an instance is no longer needed, ARC frees up the memory used by that instance so that it can then be used for other purposes.

So whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a reference to the instance. The reference is called a reference because it keeps a firm hold on that instance and as long as that reference remains the objects are not allowed to be deallocated. To ensure this, ARC keeps a count called and when an object’s reference count reaches zero the object is then deallocated. If you tried to access a deallocated instance, your app would most likely crash.

Let’s consider an example.

As you can see and objects were initialised and deallocated immediately, this is because the instances were in the method allowing it to go out of scope, letting ARC deallocate it. If those instances were initialised globally then they will not be deallocated as those instances lives in the app/playground’s scope.

When a instance is created there is a strong reference from the property to the new instance, ARC marks the instance with reference count 1, same for the instance, however when a instance is created the reference count of property is now 2 as the instance also holds on to . Naturally once the and properties are out of scope they are deallocated by ARC and the allocated memories are freed, hence the methods getting called.

Retain Cycle

As an app developer, you don’t usually have to worry about memory leaks since ARC takes care of deallocating unused objects, unfortunately this is not always the case as sometimes ARC require more information about relationships between instances in order to manage memory for you. If you don’t provide these information memory leaks can happen!

Let’s consider the same example as before but this time we are going to introduce an property to our class, like below.

We are then going to assign the object we created in our method to our pet object, like below.

Run the above scenario and you should get the following print statements.

As you can see the deallocating print statements are never called, which means the and object that we created are not deallocated due to what we call a retain cycle.

Retain cycles are caused when an object A has a strong reference to an object B and object B has a strong reference to object A causing memory to leak. This fools ARC and prevents it from cleaning up. How can we solve this?

Weak Reference

To break retain cycles you could introduce a weak relationship between objects. As mentioned before ARC maintains a count of all the strong references, but with weak references the reference count of an object is never increased. So when a property, constant, or variable references another object and is marked as , the reference count of the object remain the same.

Let’s fix the above example by marking the property in the class as . You could instead mark the owner property in pet as weak but i did not because a pet always has an owner whereas a user may not.

A weak reference is always optional and automatically becomes when the referenced object is deallocated. That’s why you must define weak properties as optional types for your code to compile

If you run the above scenario, you should get the following print statements.

Unowned Reference

This is another relationship type you could use that doesn’t increase the reference count. The difference between and is that references are never optional types. If you try to access an property that refers to a deallocated object, you’ll trigger a runtime error similar to force unwrapping a optional type.

Unowned properties are defined like so.

Retain Cycles With Closures

Like objects, closures are also reference types so if you are capturing references of objects for example in a closure there’s a chance that you could run into a retain cycle.

Let’s introduce a lazy closure property in our class.

This closure returns complete information about a user. The property is because it’s using and , which aren’t available until after the initialiser runs.

And finally let’s add the following line to the end of our function.

If you call the function, you should get the following print statements.

As you can see the object was deallocated but the object did not hence a memory leak due to a strong reference cycle between the closure and the object.

We can solve this issue by capturing an or reference to in the closure like below.

If you call the function again you should see that the object was deallocated.

Conclusion

ARC carries out most of the heavy lifting when it comes to memory management but it’s important to ensure that we provide enough information about the relationship between objects for it to work effectively. Because if you don’t, memory leaks can happen and they are usually hard to find.

I hope this article was useful and if i missed anything or you think there’s a better way, please let me know 🙂

A Software Engineer with a passion for technology. Working as an iOS Developer @BBC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store