Memory leaks in Swift. ARC (Automatic Reference Counting)
Every time a class instance is created it takes up some memory space in RAM. Many programming languages use some kind of a garbage collector to deal with this by traversing an object graph to determine wether they are still being used or not. If not, they are removed to free some space for another object.
That sounds cool, but unfortunately (or fortunately?), that’s not how it works in Swift. Garbage collectors are said to add up to 20% CPU overhead. That is the reason Apple decided not to implement it and instead, use some sort of manual memory management.
Every class instance has a retain count and this number represents a number of instances being referenced by another instance. Whenever a class reaches 0, it is removed from memory automatically.
Many properties that are a reference type will have a strong reference. This is by default. Strong references increase the retain count by one. Here is an example of a writer strong referencing a book.
Everything is fine in the example above. The book is being allocated and deallocated and the writer is also being allocated and deallocated at the end of the do scope 😀. But what do you think will happen if the book makes a reference to the writer?
You guessed it! Both of them are not being deallocated 😱. That’s because theBook has a retain count of 1 and bradStone also has a retain count of 1. The name when this happens is retain cycle. ARC will not pull them out of memory unless that count is equal to 0.
The weak reference does not add up to the retain count of an instance. That means if the book was to weak reference the writer, the retain count for writer would still be 0 and it could be deallocated by ARC and memory leaks will be avoided.
The most important part in that code 👆🏻 is on line 3. That means whenever the writer gets to be nil, the book will be deallocated too.
Like a weak reference, an unowned reference does not keep a strong hold on the instance it refers to. It does not increment the retain count. Unlike a weak reference, an unowned reference is used when the instance being references has the same or a longer lifetime.
Recommendations by Apple:
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.
If you are using a closure as an instance variable and within the closure you are accessing any property of the class, there is a retain cycle and memory is being leaked 🤷🏻♂️.
The retain cycle is a little bit harder to see, but since the book is holding a reference to the closure and within the closure, book is being referenced via self, that’s a problem.
It is really simple to fix this:
Within the closure, at the top, there is an array called capture list. The reference to self can be changed from strong to weak, thus breaking the retain cycle ✌🏻.
I hope this helped you in any way. Please let me know if you have any comments about the post.