Besides being a pillar for any great modern society, learning to give back what one gets is also one of the best practices in the mobile ecosystem. Why?
Our mobile devices are little monster of power, but their power is limited. So using it in the most efficient way is paramount. Efficiency can be achieved in several ways, from designing state-of-the-art hardware to writing platform-aware software. As mobile software developers, we can mostly contribute to the latter, and we can do so by giving back to the system all the resources we previously got and that we do not need anymore.
So, few years ago, when Apple had not yet revealed ARC, it was normal to see code similar to this
where you would first ask the OS for some memory where to store the string, perform some actions with it and when finished, you would release the memory given to you. The OS would manage the memory for you at its best, but you still needed to be a good memory management citizen and give back the resources you didn’t need anymore.
When ARC was released, Apple gave developers a huge help in being good citizens: unused resources would be claimed by the OS automatically. So the above code became
No need to
release anything anymore. Kudos for Apple
But one basic principle stayed the same, even till today Swifty world: if you
need to keep a resource around, you must create and hold a strong reference to it. As
long as you do that, no OS will take it away from you (well, besides those cases where your app would be terminated by the OS itself).
With this basic rule in mind, let’s make the whole story more interesting by mixing memory management with Swift closures (a.k.a blocks in Objective-C).
In the following code, a method on a
UIViewController subclass is used as a
delegate callback after carrying out some work. Very common scenario when
developing UIKit-based apps.
Inside the method the view controller attempts to dismiss its presented view
controller by calling
dismiss(animated:completion:) and passing a closure
needed for some cleanup. The closure knows the basic principle I mentioned above
and so is keeping a strong reference to
self through the call to
What I have seen in several code bases I worked on is the following version of the previous snippet
Here the programmer took a safe approach to the problem of memory management
with closures, and decided to avoid a retain cycle by using a capture list. In
this list, the closure is being instructed to create a
weak reference to
rather than a strong one like it would normally do. That capture list transforms
the type of
self in the scope of the closure from
UIViewController? and that explain the use of
That weakification of
self is absolutely not needed if the only reason is to
prevent a retain cycle. It’s purely defensive programming. If not paranoia programming.
So when is it ok to write
[weak self] in the capture list of a closure? Answer is pretty easy.
self holds a strong reference to the closure either directly or indirectly through other objects, then you have to weakify it like in the following snippet:
There is another reason though where you would want to weakify
self in a closure. That reason has nothing to do with memory management and it is purely behavioral. A classic example is when performing an asynchronous network call as part of the lifetime of a view controller, like when you go to a screen displaying data which must be fetched from a remote server.
In that case you would create a view controller, present it, enqueue a network request and finally inform the user with a loading indicator. If the user leaves the screen before the network sends back the data, when this finally arrives you want to do nothing with it. The view controller is not on screen anymore so why bother?
Weakifying the controller would let you discard that data while a strong reference would keep the controller around even if the user has already left the screen. And this can be the source of some unexpected bugs.