iOS Swift Memory Optimisation

This post is a result of a work problem we had, one of our app was using a lot of memory and that usage was making the app very unstable. As I was researching this issue, I found a lot of posts and stack overflow answers but nothing consolidated. So, I thought of writing something that’ll give you an idea about where an app’s memory usage can be optimised.

This post will contain the issues I faced during our app development.


1. First thing I tackled was strong references in app

While researching I found about strong references and how delegates play a fairly big role in their creation. I came across this beautiful and concise post by NatashaTheRobot https://www.natashatherobot.com/ios-weak-delegates-swift/ (thanks Natasha!!).

While optimising, I came across lines like this

var customDelegate: CustomDelegate?

This property was holding a strong reference to my view controller, which prevented it from ever being deallocated, causing memory to climb fairly rapidly. After changing this reference to weak, solved much of the memory problem.

weak var customDelegate: CustomDelegate?

Also, I had a Fab class which helped in adding fab button to view controller, here I found a cycle where I was passing controller’s reference to Fab class and having a Fab reference in my view controller hence neither of them got deallocated, solved this problem with this line

weak var fabButton: Fab?


2. Strong references in closures

I tried to find other places of strong references and came across how closures affect app’s memory usage. I came across this post by kelan.io, this is a great post explaining how strong self reference in closure can prevent the controller from deallocating, now I was not a big fan of guard in closure to unwrap weak self and did not wanted to risk using unowned as explained in this
Stack Overflow answer http://stackoverflow.com/a/24320474

The difference between unowned and weak is that weak is declared as an Optional while unowned is not. By declaring it weak you get to handle the case that it might be nil inside the closure at some point. If you try to access an unowned variable that happens to be nil, it will crash the whole program. So only use unowned when you are positive that variable will always be around while the closure is around

To get rid of this, I came across keyword @noescape while reading this answer http://stackoverflow.com/a/28428521

Adding @noescape guarantees that the closure will not be stored somewhere, used at a later time, or used asynchronously.
From the caller’s point of view, there is no need to care about the lifetime of captured variables, as they are used within the called function or not at all. And as a bonus, we can use an implicit self, saving us from typing self.

Though I had to use weak self in asynchronous networking closures but thats Okay!


3. Other problems noticed

NSTimer
I noticed that timers actually held a strong reference to the controller and not allowing the controller to get deallocated, I found an article online which asked to invalidate the time in dealloc method, but since timer has a strong reference dealloc will never be called, so that didn’t work for me.

Hence, I invalidated the timer in func viewDidDisappear(_ animated: Bool) and voilà it worked 🙌

UIGraphicsGetImageFromCurrentImageContext

While exploring I found people had memory problems when getting image from context and guess what I too had this line in my code
let outputImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()

One of the solutions I found was http://stackoverflow.com/a/23875557, but fortunately for me I was able to remove the complete code piece.

Hope this helps :)