10
votes

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?

5

5 Answers

13
votes

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.

13
votes

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.

1
votes

There are correct answers, but I really do not know, whether they are answers to your Q. They explain the problem of retain cycles with blocks using self in general, but your Q was:

So why not just strongSelf = self?

The answer to this Q:

If one would do this, self would be a part of the block's closure and always be retained. The whole story with weak self would be meaningless.

0
votes

In simple words

__weak typeof(self) weakSelf = self - We use this just before block,

This is just pointer to self, no retain cycle started

-- Retain will be done if and only if block will execute

--> If we make it strong then it will start retain cycle and will consume memory, even if we don't call block

0
votes

One point must be cleared that you are not using weak/strong pattern to avoid retain cycle! Whether you use a strong reference to self or to weakself, you are not avoiding retain cycle. Retain cycle is broken by the reference variable scope! When it reached the end of the scope, the reference variable is dealloced. The weak/strong pattern is just a protection mechanism that prevent you make a strong reference to nil, since before the block is created and run, self maybe dealloced.