9
votes

Why is it necessary to have a strong reference to a weak reference inside a block?

I understand that having a weak reference inside the block will avoid retain cycles. But why must there be a strong reference to the weak one again?

Background:
As described by Mason this is best practice.

I know the proper way to refer to self inside a block is to create a weak reference outside the block, and then a strong reference to that weak reference inside the block[...]

Example:

__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
    typeof(self) strongSelf = weakSelf;
    // code using strongSelf
});
2
it is not really necessary to make a pointer strong again inside the block.holex
A much more beautiful and clean way is using @weakify(self) and @strongify(self) if you use libextobjlukas_o
it might be more beautiful, but that is not part of the official language.holex
@holex "it is not really necessary to make a pointer strong again inside the block". Why? the weak pointer might go nil, in mid of the block execution.BangOperator
@BangOperator, so what happens then? if the actual object is about being released anyway then block also loses its purpose in the most of the cases.holex

2 Answers

15
votes

Imagine that the last remaining strong reference to self is held on a different thread to the one that your block runs on.

Now this happens:

__weak typeof(self) weakSelf = self;
void (^someBlock)(id) = ^(id data){
    if (weakSelf != nil) {
       // last remaining strong reference released by another thread. 
       // weakSelf is now set to nil.
       [myArray addObject:weakSelf];
    }
});

This will crash with an NSInvalidArgument exception for adding nil to an array.

Making the reference strong before use removes the potential race condition and ensures that the pointer will always point to the same object.

If you are 100% certain that an object will only ever be referenced by one thread, it isn't strictly necessary to do this. But it's bad practice to make that assumption.

6
votes

It's not inherently necessary, but the general idea is to make sure that the object pointed to by weakSelf is not dealloc'ed while the block is executing. Creating the strong reference has the side effect of retaining the object. That retain will be released by ARC when the strong reference goes out of scope. It's largely defensive. Generally speaking, you should aim to provide other (better) guarantees that your system remains stable during block execution.