paint-brush
Swift: Avoiding Memory Leaks by Examplesby@BarekJaafar
10,768 reads
10,768 reads

Swift: Avoiding Memory Leaks by Examples

by Jaafar BarekJanuary 23rd, 2019
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

In Swift Automatic Reference Counting (ARC) is used to manage memory usage in an iOS application.<br>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.<br>You as a developer don’t need to do anything for that management&nbsp;, except for 3 cases were you need to tell ARC more information about relations between instances to avoid “Retain Cycles”.

Company Mentioned

Mention Thumbnail
featured image - Swift: Avoiding Memory Leaks by Examples
Jaafar Barek HackerNoon profile picture

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Art/memory_management_2x.png



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 Cycles:

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.

The 3 cases that cause memory leaks:

1- Strong Reference Between 2 Classes:

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:

Weak References

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.

Unowned References

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.

2- Class Protocol Relation:

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

3- Strong Reference Cycles for Closures:

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

Conclusion

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.

Some Great References about ARC:

Read my previous article about GCD in Swift:


Swift Multi-Threading using GCD For Beginners._Optimize your application performance and user experience using GCD._medium.com