ReactiveSwift - Manage your memory!
Memory management is a pretty important issue when talking about any kind of system. You can’t pretend that your resources are unlimited, and give them out no matter what. When working with
ReactiveSwift it’s really easy to fall into the pit of wasted resources if you don’t follow simple rules.
Basic unit that will help us handle our memory management, when working with
disposable. At the same time that you start observing
Signal, or start any work with
Signal Producer, you will gain access to such
Disposable. If you are not interested in results that come through that
Signal, you can simply call
.dispose() method on that
disposable, and you won’t receive updates any more. This also means, that as soon as
SignalProducer notices, that nobody is interested in it’s results, it can stop it’s work and clean resources.
It’s common to free any resources when you exit a screen in your application. This means, that you should dispose all your
disposables as well. Of course it would be hard to store each
disposable in separate variable and dispose when you’re not interested in updates anymore. That’s why we can use a container for such
CompositeDisposable. You can basically throw any
disposable inside this container, and dispose all of them at once when your view controller deinitializes.
Let’s take a look at how to work with disposables.
What will happen here?
Producer does not start it’s work until
startWithValues is called. After that, we have to actions scheduled that will send us values
2. They will also perform some heavy calculations. After two seconds, I decide that I’m not interested in any results, so I dispose received
disposable and I will not receive any updates in
startWithValues block anymore. However, work in producer has been already scheduled. That’s why I put the
if statement checking if someone is still interested in producer’s work. If not, I will not perform that.
In this example, Let’s imagine that you create your
disposables variable at the time you initialize your class. Then, when you start observing any signals, you add each
disposable to your container. You can dispose them any time you want, but most often, you will do it at the time that you dealloc your controller, so you can add this code to
You may have noticed, that there are parts where are use
[weak self] and
[unowned self]. Let’s take a closer look at this!
Working with closures
Disposables are one important thing that will lead you to memory management heaven. Next things that you have to remember about when working with ReactiveSwift is to manage relationships in closures that you pass to observers. When you do anything with a
self variable in such closure, you create a retain cycle, as you hold strong reference to
self. Controller holds a closure and closure holds controller. No way that they will be released any time soon. To have a weak reference to
self, you can add
[weak self] or
[unowned self] to such closure. If you do not add one of those statements, your
deinit method will not be even reached, as controller will not be deinitialized.
What is the difference between
[weak self] and
[unowned self] you ask?
When you use
[weak self], you tell your closure, that it is possible that
self could be
nil at some point. I usually put a
guard let statement at the beginning of this kind of closure, so if
self is nil, I don’t continue with any operations.
On the other hand, we have
[unowned self] that doesn’t tell us that
self could be
nil at some point. It’s on our side to take care of that and make sure that this block will not be called if
self is deinitialized. If you properly take care of
disposables, most often
[unowned self] is a safe bet, as those closures will not be executed after deinitialization of
A note to first example
Let’s get back to the code from first example. You can see, that I used a
[weak self] for the
[unowned self] for the observer. Why did I do that?!
When I start observing for values from producer in
startWithValues closure, I’m pretty sure that I’ll call
dispose when my controller deinits, so I know that
self will be there if I need it. With given
SignalProducer that’s a bit different. It is accessible from outside. Let’s imagine, that I’ve saved this producer at the time that this class was alive, and started it’s work after it was deinitialized. If I had
[unowned self] there, then it would cause a crash. As long as I have
[weak self], at the beginning of my producer’s work I can check if
self exists and If it doesn’t I can discontinue with any other work. If it does, I’ll create a reference to
self and proceed with my work.
There are always edge cases, that may cause a headache when choosing between
weak, but as the time goes, you’ll find it easier and easier to work with them! See you next time!
This article is cross-posted with my my personal blog.