PromiseKit states the following on their website:
Should I be concerned about retain cycles?
tl;dr: it’s safe to use self in promise handlers.
This is safe:
somePromise.then { self.doSomething() }
Provided
somePromise
resolves, the function passed tothen
will be released, thus specifying[weak self]
is not necessary.Specifying [unowned self] is likely dangerous.
You’re telling me not to worry about retain cycles?!
No, it’s just that by default you are not going to cause retain cycles when using PromiseKit. But it is still possible...
Does this mean I should never use [weak self]
in PromiseKit blocks? Are there ever situations where I would still need to use [weak self]
? How exactly is it preventing a retain cycle?
Using [weak self] is only required within situations in which capturing self strongly would end up causing a retain cycle, for example when self is being captured within a closure that's also ultimately retained by that same object.
In Swift, [weak self] prevents closures from causing memory leaks in your application. This is because when you use [weak self], you tell the compiler to create a weak reference to self. In other words, the ARC can release self from memory when necessary.
Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization. In general, be very careful when using unowned.
TL;DR: Continue using [weak self]
in PromiseKit blocks to prevent objects from living longer than necessary.
There are a few things to note. First, there are 2 primary reasons to use [weak self]
in a block:
Second, PromiseKit is creating a retain cycle when you call that block of code. self
is holding on to somePromise
usually, and somePromise
is holding on to self
. The reason that they say you shouldn't be concerned with this retain cycle is because the retain cycle is going to get broken automatically by PromiseKit. When then
is released, somePromise
will no longer hold on to self
, thus breaking the retain cycle.
So we know we don't need to worry about problem #1 with PromiseKit blocks, but what about problem #2?
Imagine a view controller fires off a network request promise and that it's going to take 30 seconds until this promise is resolved. Now before it's resolved, the user presses the back button. Normally UIKit is going to deallocate the view controller since it is no longer on screen and the system can save resources. However, since you referenced self
in the promise, it can no longer be deallocated. This means the view controller is going to live 30 seconds longer in memory than is necessary.
The only way to resolve problem #2 is by using [weak self]
inside the block.
Note: One could argue that when your view controller backs out, you should cancel the ongoing promise anyways so that it releases the hold on self
. However, figuring out when a view controller should be deallocated is not a simple task. It's much easier to let UIKit handle the logic for you and if you do indeed need to do anything when a view controller is deallocated, implementing it in the view controller's dealloc
method. This won't work if the block is holding on to the view controller strongly.
Update: Looks like one of the authors did talk about this and clarified the reasons for making those recommendations:
In fact, retaining
self
is probably what you want so to allow the promise to resolve beforeself
is deallocated.
That documentation is merely saying that you don't have to worry about PromiseKit introducing "strong reference cycles" (previously known as "retain cycles") because when the promise is fulfilled and the block finishes running, those strong references are automatically resolved for you. The choice of strong vs weak references is solely up to you.
For example, there's no need to keep a strong reference to a dismissed view controller if you are simply updating UI elements on scene that no longer exists. You'd use weak
in that scenario. But sometimes you want strong reference (e.g. you may want to update the underlying model to reflect the success or failure of the promise).
Bottom line, all they're saying is that you shouldn't let PromiseKit dictate the strong vs weak references, but rather it should be driven by your app's broader design requirements. The only hard rule re PromiseKit is that you should avoid unowned
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With