Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Breaking retain cycle with strong/weak self

I've read posts about strong/weak self to break retain cycles but I am still confused as to how they work. I understand the use of __weak typeof(self) weakSelf = self to create a weak reference to self but I am confused about strong reference. As I understand it, the strong reference is so that there is a strong reference to self so that it doesn't get deallocated before the end of the block right? So why is it necessary to have __strong typeof(self) strongSelf = weakSelf? Doesn't this end up pointing to the self object anyway? So why not just strongSelf = self?

like image 486
somtingwong Avatar asked Jul 08 '15 02:07

somtingwong


People also ask

Should we always use weak self in closure?

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.

How do you break a cycle to keep it?

In order to prevent this retain cycle, we need to declare at least one of the variable as weak or unowned. We can break the retain cycle with adding a weak keyword before either the driver property of the Car class or the car property of the Person class.

Do we need to use weak self or unowned self in this closure?

“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 initialisation.” Save this answer.

How do you use a weak self in closure?

To break a strong reference cycle in a closure, use [weak self]. This makes the closure weakly reference self. When you use [weak self], remember that self becomes optional. Thus, you need to handle optionals in a closure that weakly references self.


2 Answers

Any non-weak object that you reference inside the block will result in an implicit retain on that object, as the block is being created. Not executed, but created.

If you initialised the inner strongSelf directly from self, you will retain the value of self and potentially cause a retain cycle.

On the other hand, if you initialise it from weakSelf, you will not retain the value of weakSelf.

This is the reason for the two-step. The outer code copies the value of self into weakSelf, but ARC does not add a retain because it is __weak().

The block "creation" copies the value of weakSelf (or at least, manages to makes its value available at execution time). You can't see where it copied it to, but it did.

At block "execution" time, the block copies the "value of weakSelf" (which will be nil if self has been dealloc'ed in the mean time) into strongSelf which ARC then applies a retain to. Thus, for the duration of the block, the object referenced by strongSelf will remain alive, if it was alive to begin with. If you had only relied on weakSelf, it could go nil at any time during the execution of the block.

Note that weak/strong pattern is belt-and-braces - many examples actually rely on the fact that the weakSelf will go nil, and the block will silently become a collection of no-ops (messages to nil).

Retain cycles typically only occur if (a) you keep a reference to the block in a self.property or (b) you hand the block off to some other object (notification manager, etc), and tell that other object to forget it in your dealloc; in both cases your dealloc will never be called while the block is alive.

When people say "the way to do this stuff is with the weak/strong pattern", they are assuming the worst possible scenario.

like image 157
Jeff Laing Avatar answered Sep 29 '22 22:09

Jeff Laing


The pattern is:

__weak typeof(self) weakSelf = self;

[manager someAsynchronousMethodWithCompletionHandler:^{
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        ...
    }
}];

The idea is that the completion handler block will have only a weak reference to self, so that if self is released before the completion block is called, then it will safely be deallocated because the block has no strong reference to it. (A common example is when a view controller initiates some asynchronous network request to update a view, if the view controller is dismissed before the network request finishes, there's no point on hanging onto the view controller instance for a view that is long gone.)

But, this weakSelf/strongSelf pattern also ensures that if the opposite happens, that the completion block has started and encounters the strongSelf line before self is released, the block will ensure that self is retained for the duration of the running of that block (i.e. it can't get deallocated half way through the running of the completion block, even if this is running on a different thread). This has a number of potential benefits (ranging from object integrity to the elimination of race conditions). Sometimes you don't actually need the strongSelf half of the "weakSelf/strongSelf dance", but it's an invaluable tool when needed.

If, however, you had a line inside the block that said, typeof(self) strongSelf = self (instead of weakSelf), the mere presence of self in the righthand side of that statement would result in the block maintaining a strong reference to self up front, entirely defeating the purpose of using weakSelf in the first place.

like image 40
Rob Avatar answered Sep 29 '22 23:09

Rob