SaltyNuts SaltyNuts - 3 months ago 28
iOS Question

Should I use weakSelf in nested blocks?

I'm trying to correctly avoid retain cycles with blocks in Objective C, and am not sure about having nested blocks.

If I write a simple block like this:

[self doSomethingWithBlock:^{
[self doSomethingElse];
}];


The compiler catches and warns me that this could cause retain cycles. I change it as follows to avoid the cycle:

__weak __typeof(self)weakSelf = self;
[self doSomethingWithBlock:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf doSomethingElse];
}];


When I write something like this:

[self doSomethingWithBlock:^(MyObject* object){
[object doSomethingElseWithBlock:^{
[self doYetAnotherThing];
}];
}];


The compiler is happy, but I'm not convinced that it's safe. Even though there is an intermediary
object
in between, it still looks conceptually the same as above, but now it's a cycle with 3 retains.

Should it be like this instead?

[self doSomethingWithBlock:^(MyObject* object){
__weak __typeof(self)weakSelf = self;
[object doSomethingElseWithBlock:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf doYetAnotherThing];
}];
}];


Or like this?

__weak __typeof(self)weakSelf = self;
[self doSomethingWithBlock:^(MyObject* object){
[object doSomethingElseWithBlock:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf doYetAnotherThing];
}];
}];

Answer

In this situation, you are not worried about cyclic references. What you are worried about is a situation where the object self isn't actually needed anymore, but using self inside a nested block would keep it unnecessarily alive. For example, if you have a view controller that should go away when the view is removed by the screen, but you download an image that you would like to display in the controllers view. If the image arrives long after the view is already gone, you don't want the view controller alive anymore.

Best is

__weak typeof (self) weakSelf = self;

before calling the outermost method. Then within every block that ought to use self, you add

typeof (self) strongSelf = weakSelf;

and use strongSelf within that block. Depending on the situation, you might want to check that strongSelf isn't nil at that point, but sending messages to strongSelf when it is nil has no effect, so if all you do is sending messages and getting or setting properties, then a check for nil is not necessary.

What happens if you don't do this? The difference will be that self may be kept alive unnecessarily into the innermost block, if you use self everywhere (or just in the innermost block).