Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would I not use a weak pointer to self in a Block passed to dispatch_after()?

I have seen the following used:

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    //code to be executed on the main queue after delay
    [self doSometingWithObject:obj1 andAnotherObject:obj2];
});

But shouldn't it use weak self in the block?

__weak typeof(self) weakSelf = self;
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    //code to be executed on the main queue after delay
    [weakSelf doSometingWithObject:obj1 andAnotherObject:obj2];
});

I'm newish to GCD and Blocks and trying to work out the most correct usage. Many thanks on any guidance on this one.

like image 534
FlimFlam Vir Avatar asked Jan 12 '16 18:01

FlimFlam Vir


1 Answers

It depends upon the desired behavior.

  • The first syntax (referring to self in the block) will maintain a strong reference to the view controller until the dispatch_after fires and doSometingWithObject successfully run. This will happen even if the view associated with that view controller is dismissed in the intervening period.

    So, you'd use this pattern only in cases where you absolutely need that method to run, even after the view associated with that view controller was dismissed. For example, if that method is updating some model objects, saving something to persistent storage, posting some network request, etc.

  • The second syntax (the weakSelf pattern), will not maintain a strong reference to the view controller, and thus if the view associated with the view controller was dismissed by the time the block runs, the view controller will be released and weakSelf will be nil, and thus doSometingWithObject will not be called. (Obviously, if the view has not yet been dismissed, the view controller will not have been released, weakSelf will not be nil and that method will be called.)

    You will do that if the method in question only needs to be called if the view has not yet been dismissed. For example, if the sole purpose of the method is to update some UI object on that view, you obviously don't need to do call that method if the view has been dismissed already. And in that scenario, you'd generally prefer the use weakSelf so that the view controller is promptly released when it is no longer needed.

  • Just for the sake of completeness, there is actually a third permutation of this pattern, sometimes (jokingly) called the weakSelf/strongSelf "dance":

    __weak typeof(self) weakSelf = self;
    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        //code to be executed on the main queue after delay
        typeof(self) strongSelf = weakSelf; 
        if (strongSelf) {
            [strongSelf doSomethingWithObject:obj1 andAnotherObject:obj2];
            [strongSelf doSomethingElseWithObject:obj1];
        }
    });
    

    This pattern is very similar to the second example, where the method(s) are not called if self is deallocated. You use this pattern when you want a weak reference, but either (a) you need to ensure that it isn't deallocated while the block is running; or (b) when you need to test to see if it is nil or not, but want avoid race conditions.

like image 177
Rob Avatar answered Oct 21 '22 00:10

Rob