2

I need to execute same bunch of code in two blocks (I'm using ARC):

__weak typeof(self) weakSelf = self;
[_dataProvider doA:^(NSError *error) {
    [weakSelf handleError:error];
}];

And in a different place i call:

__weak typeof(self) weakSelf = self;
[_dataProvider doB:^(NSError *error) {
    [weakSelf handleError:error];
}];

Then I have my handler:

- (void)handleError:(NSError *)error {
    [self.refreshControl endRefreshing];
    [self.tableView reloadData];
}

Is it save to use it this way? Please do notice that handleError: method uses self inside. If not, then what is the proper approach here? BTW: self is a viewController and can be dealloced (doB: and doA: blocks are based on networking, so can be slow).

Nat
  • 12,032
  • 9
  • 56
  • 103

1 Answers1

2

It is not safe to do this, even if many people a doing it like this.

You should use the "weakSelf" pattern with blocks when it is justified. In your example the "weakSelf" pattern is not justified, because self don't have any strong reference to your block. You can use like this :

[_dataProvider doA:^(NSError *error) {
    // here you can use self, because you don't have any strong reference to your block

    [weakSelf handleError:error];
}];

Use "weakSelf" pattern if you have a strong reference to your block ( with a property or an instance variable for example) and your are capturing self inside the block, example :

 @property(strong) void(^)(void) completionBlock;
....

__weak typeof(self) weakSelf = self; 

    self.completionBlock = ^{
      // Don't use "self" here, it will be captured by the block and a retain cycle will be created
      // But if we use "weakSelf" here many times, it risques that it will be nil at the end of the block
      // You should create an othere strong reference to the "weakSelf"
      __strong typeof(self) strongSelf = weakSelf; 
      // here you use strongSelf ( and not "weakSelf" and especially not "self")
    };
samir
  • 4,501
  • 6
  • 49
  • 76
  • I heard something similar. However xCode isn't agreeing with this as far as I understand- `[_someInstance doC:^(NSError *error) { self.index += 5; }];` (where `@property (nonatomic, assign) NSInteger index;`). XCode claims `Capturing 'self' strongly in this block is likely to lead to a retain cycle`. I have neither property nor ivar for this block, why do I get the warning? – Nat Jun 26 '14 at 12:26
  • I will silence the warning by doing : #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" ....your block here #pragma clang diagnostic pop – samir Jun 26 '14 at 12:40
  • So you claim this is a general warning and I shouldn't care about it in this specific case? I usually find warnings helpful and I'm afraid the warning have some 'truth' hidden behind it. However if you're sure in this case it's ok then I understand the pattern how it works. – Nat Jun 26 '14 at 12:46