11

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.

jscs
  • 63,694
  • 13
  • 151
  • 195
FlimFlam Vir
  • 1,080
  • 9
  • 15
  • 2
    It depends. Do you need `doSometingWithObject` [sic] to be called even after you dismiss the view controller or not? Sometimes you do (e.g. perhaps you're saving something, updating a model object, posting some important network request, whatever), in which case you'll use the former syntax. But sometimes you don't (e.g. you want to update some UI object on a view that may have been dismissed already), in which case you'll use the latter. – Rob Jan 12 '16 at 19:03
  • 1
    It depends on what you want to happen if `self` has a chance of being deallocated before the delay is up. The first snippet would prevent that so the call in the block always happens where the second one would allow self to be deallocated and the block wouldn't do anything. Usually weak self is used to prevent retain cycles but there isn't a retain cycle in this block either way – dan Jan 12 '16 at 19:03

3 Answers3

12

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.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
2

A weak pointer to self is used to prevent retain cycles. There's no risk of a retain cycle in the first code snippet.

A retain cycle would be a concern if your object were to retain the block which retains your object, and if your object were to only release the block when it itself was being deallocated. Neither of those conditions hold in this case.

dispatch_after() will run the provided block after the designated time and will then release the block. That releasing of the block is not dependent on your object being deallocated. There's no retain cycle.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
-2

Better part of using block is like this:

__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
    __strong __typeof(weakSelf)strongSelf = weakSelf; 
    [strongSelf doSometingWithObject:obj1 andAnotherObject:obj2];
});

Creating __strong reference within block will not increase the memory reference count. It will get released, once the block will get complete.

https://dhoerl.wordpress.com/2013/04/23/i-finally-figured-out-weakself-and-strongself/

Ankit Thakur
  • 4,739
  • 1
  • 19
  • 35
  • The `__strong` reference within the block *does* increase the reference count - but only while the block is running. After the block is finished it will reduce the count again. – Nef10 Jul 08 '17 at 00:01