objective-cobjective-c-blocksweak-referencesretain-cyclestrong-references

weakself inside dispatch_async queue(dispatch_get_main_queue(), ^{})


Below code snippet is in objective C

__weak MyView *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf.activityIndicatorView stopAnimating];
    [weakSelf.activityIndicatorView removeFromSuperview];
    weakSelf.activityIndicatorView = nil;
});
  1. Will the weakSelf always available/valid since it is inside the main queue?
  2. Do we need to declare strongSelf only when block is other than the main queue?

Solution

  • Your code snippet is too small to answer on your questions fully.

    1. weakSelf can be both nil or non-nil. The keyword weak means that variable weakSelf can become nil in some cases. For example, if your controller has the following property:

      @property (retain) MyView* myView;
      

      In some cases you dismiss this controller and after that you call the method f for myView:

      [self dismissViewControllerAnimated:YES completion:^{
      
          [self.myView f];
      }];
      

      Code of the method f is based on code snipped you provided in this question:

      -(void)f {
      
          [self removeFromSuperview];
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
      
              __weak MyView *weakSelf = self;
              dispatch_async(dispatch_get_main_queue(), ^{
      
                  [weakSelf.activityIndicatorView stopAnimating];
                  [weakSelf.activityIndicatorView removeFromSuperview];
                  weakSelf.activityIndicatorView = nil;
              });
          });
      }
      

      I guess you will see in debugger that the weakSelf will be nil when you will try to call stopAnimating for activityIndicatorView. And I guess you can easily reproduce the situation when weakSelf will be not cleared. It means that the answer on your first question is "No, the weakSelf will be not always available/valid and the main thread does not protect you from nil in this variable"

    2. You need to use strongSelf (__strong instead of __weak) if you don't want to loose a reference to variable inside block. For example, if in the class MyView there is a method log that logs some debug information:

      -(void)log {
      
          NSLog(@"LOG");
      }
      

      And if you want to log information always after the code in your code snippet will called use the following version of the method f:

      -(void)f {
      
          [self removeFromSuperview];
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
      
              __strong MyView *weakSelf = self;
              dispatch_async(dispatch_get_main_queue(), ^{
      
                  [weakSelf.activityIndicatorView stopAnimating];
                  [weakSelf.activityIndicatorView removeFromSuperview];
                  weakSelf.activityIndicatorView = nil;
                  [weakSelf log];
              });
          });
      }
      

      So, the answer, on your second question is "No, you need to use __strong based on your application, the block can be completed in different threads".