In Swift Automatic Reference Counting (ARC) is used to manage memory usage in an iOS application.Each time you create a new instance of a class ARC allocates a chunk of memory to store information about it, and automatically frees this memory when that instance is no longer in need.You as a developer don’t need to do anything for that management , except for 3 cases were you need to tell ARC more information about relations between instances to avoid “Retain Cycles”.
In this article we will walk together in the process of managing these 3 cases , and see real examples of retain cycles and how to get rid of them. But first, what are retain cycles and why we need to avoid them?
Retain Cycle is the case when 2 objects have strong reference to each others and are retained , make it impossible for ARC to release those object from the memory and cause what we call a “memory leak”.
Memory leaks are dangerous in you app because they will affect your app’s performance and might lead to crashes when the app runs out of memory.
Suppose we have 2 classes (Author&Book) that directly reference each other :
Theoretically this should print that both objects were allocated , and then de allocated because they were set to nil but instead it prints the following:
Author Object was allocated in memoryBook object was allocated in memory
As you see both objects were never released from memory because a retain cycle occurred when both classed had strong reference to each others.
To solve this we can declare on of the references to be weak or unowned as follows:
This time both objects will be released and the console prints the following:
Author Object was allocated in memoryBook object was allocated in memoryAuthor Object was deallocatedBook Object was deallocated
The problem was solved and ARC was able to clean the memory chunk when the objects were released just by making one of the references weak , but what does weak and unowned actually mean? According to apple’s documentation:
A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. This behavior prevents the reference from becoming part of a strong reference cycle. You indicate a weak reference by placing the
weak
keyword before a property or variable declaration.
Like a weak reference, an unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime. You indicate an unowned reference by placing the
unowned
keyword before a property or variable declaration.
Another cause for memory leaks can be a strong relation between a protocol and a class. In the following example we will take a real world scenario were we have a TablViewController Class and a TableViewCell Class , when the user presses a button in the TableViewCell it should delegate this action to the TablViewController as follows:
Normally , when we dismiss the TableViewController , deinit should be called and the print statement should appear in the console , but in this case since TableViewCellDelegate and TableViewController have strong reference to each other they will never be released from memory.To solve this we can simply adjust the TableViewCell class to be as follows:
This time dismiss the TableViewController and see the console:
TableViewController is deallocated
Suppose we have the following ViewController:
Try dismissing ViewController , the deinit method will never be executed.The reason why is because the closure captures a strong reference of the ViewController. To solve this we need to pass self as weak or unowned as follows:
This time when dismissing ViewController the console will print:
ClosureViewController was deallocated
There is no doubt ARC do an amazing job managing memory for our application , all we have to do as developers is to be aware of strong references between classes , between a class and a protocol , and inside closures by declaring weak or unowned variables in those cases.
Swift Multi-Threading using GCD For Beginners._Optimize your application performance and user experience using GCD._medium.com