Memory Management in Swift

A well memory managed app doesn’t take any extra space than it needs. Finding memory leaks in an app is not easy, instead understanding the way iOS memory management works is trivial. In this article I tried to clarify how and when memory allocation and deallocation happens in iOS specifically in Swift. And I also tried to give an overview of retain cycles which is one of the most common causes of the memory leaks.

Automatic Reference Counting

Swift inherited its memory management system from Objective-C which is called Automatic Reference Counting. ARC uses object ownership concept which means it destroys the objects and releases them from the memory if the object has no owner anymore.

  • Reference count: In order to manage the object ownerships, ARC uses a concept called reference count. Claiming an ownership of an object, increases the reference count of that object by one. As soon as the reference count comes down to zero, the object will be released.
  • Strong reference claims the ownership of the object and increments the reference count. As long as someone has a strong reference to an object, ARC will not generate the release message for the object and it won’t be released. In Swift all the references are strong if not specified.
  • Weak: If an object is created using weak keyword, it has no owner.

If you’re still not comfortable with the strong vs. weak concept, think of the object as balloons (this is the best explanation I've ever seen for this subject, many thanks to Martin for this clear simplification). A balloon won't fly away (released) as long as at least one person is holding a string to it. The number of people holding strings is the retain count. Many people can have strings to the same balloon. A strong reference is like holding on to a string to that balloon. As long as you are holding on to a string attached to the balloon, it will not fly away. A weak reference is like looking at the balloon. You can see it, access its properties, call its methods, but you have no string to it. If everyone holding onto the string releases the balloon, it flies away.

Swift always uses atomic updates to the reference count, because it does not know whether two threads could be trying to update the count at the same time.

Retain Cycle

Retain Cycle or Strong reference cycle happens when two objects have strong references to each other. Their reference counts never go to zero so they never get deallocated. Retain cycle happens with different scenarios. Here is a list of most common ones:

  1. Hierarchical relationships
    Parent class should always have a strong reference to its child classes (this a is convention not a rule, all we have to be sure about is that we are not making a two way strong references, it should be either parent to child or child to parent). When a child wants a reference to its parent, though, it should make it a weak reference by using the weak keyword. In simpler words object must never retain its parent or any hierarchical ancestor.
  2. Mutually dependent objects
    When two objects have reference to each other, one should use weak reference to avoid the retain cycle. You can find the famous example of Tenant-Apartment in Swift documentations.
  3. Closures
    If any variable is declared outside of the closure’s scope, referencing that variable inside the closure’s scope creates another strong reference to that object (except Ints, Strings, Arrays, and Dictionaries in Swift because they are value types). In other words, class retains a closure that captures self strongly. Capture list defines how the variable references are captured in the closure. By default, if you don’t use a capture list, everything will be strongly referenced. To avoid retain cycle, use weak or unowned reference to self in closure's capture list.
  4. Delegates
    Usage of Delegates can cause a retain cycle if the delegate is not set to be weak because most delegates are referencing classes that they do not own.

weak and unowned Keywords

The purpose of using the weak and unowned keyword is to avoid strong reference cycles. Both of them do not increase the reference count of the object being referred and will assign an instance without keeping a strong reference to it.

weak is used when you know that reference is allowed to become nil so it has to be defined as an optional variable. They will be mutated to nil after deallocation.

unowned is used when you are certain that reference will never become nil so it has to be defined as non-optional since it is assumed to always have a value.

Here there are few lines I found helpful from Swift documentations: Use an unowned reference only when you are sure that the reference always refers to an instance that has not been deallocated. If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.

Which one to use?
When two instances are optionally related to each other weak is the right option.
There are times when two class instances are related to one another, but one of those instances cannot exist without the other one (e.g. area code for a phone number). They are mutually dependent, so they will always be deallocated at the same time. This is the case unowned should be used.

There is an important catch with using unowned, You can think of unowned as a weak property that is implicitly unwrapped (though unowned has slight performance improvements on account of completely ignoring reference counting). So if you are using unowned, you have to be careful of the cases that variable becomes nil.

Reference types vs. Value types

Struct and Enum are value types means when a new instance is made, their values are copied instead of increasing its reference count, so they don't make strong reference cycles. It means that if you are dealing with value types you don’t even need to worry about specifying strong or weak for them. To lean more about the differences between value types and reference types check this post.

Further Study

Automatic Reference Counting
Interview Questions: How is memory management handled on iOS?
Retain Cycles, Weak and Unowned in Swift
“Weak, Strong, Unowned, Oh My!” — A Guide to References in Swift
Strong, Weak, and Unowned — Sorting out ARC and Swift
Capture List

--

--

--

iOS Developer, computer science freak

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Centalising log files of a Spark application running on EMR

How big data works?

Laravel 9 — full text index

Solving Complexity with Networks

Deploy your application to Digital Ocean using Docker and Bitbucket Pipelines

How To Test Exceptions In Python With Pytest And With Statement

Surviving the Coding Bootcamp — From no coding experience to earning a six-figure salary

How to perform CRUD operations using Blazor Server App Part-I

Screenshot of blazor template screen.

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
Masih Tabrizi

Masih Tabrizi

iOS Developer, computer science freak

More from Medium

How to send SMS Messages with Swift and Vapor using Async/Await

Subscripts in Swift

Combining Operators In RxSwift

How to create an Xcode project and connect it to Github?