简体   繁体   中英

Block capturing 'self' strongly

I have the following action for a button, which toggles whether an object is shown as favorite or non-favorite:

- (IBAction)addToFavorites:(UIButton *)sender {
  if ([object isFavorite]) {
    [_apiManager removeFromFavorite:[object ID] withCompletion:^ {
      [_favoriteButton setImage:[UIImage imageNamed:@"favorite"] forState:UIControlStateNormal];
    }];
  }

  else {
    [_apiManager addToFavorite:[object ID] withCompletion:^ {
      [_favoriteButton setImage:[UIImage imageNamed:@"favorite_yellow"] forState:UIControlStateNormal];
    }];
  }
}

Both completion blocks are identical, with exception to the image name. XCode is giving to the else case the warning: Capturing 'self' strongly in this block is likely to lead to a retain cycle and pointing at _favoriteButton . However, the same does not happen in the case when the if condition is true.

I imagine that either both or none of the cases should present the warning, and I don't understand why only the later shows it. Is this an Xcode bug? Are both causing retain cycles?

_favoriteButton is an ivar. It is owned by a specific instance of your class, so using it captures the current self in the block ( Reference to instance variables inside a block )

Instead, you should create a weak reference to self, and use property accessors, like this :

- (IBAction)addToFavorites:(UIButton *)sender {
  __weak YourViewControllerClass *weakSelf = self;
  if ([object isFavorite]) {
    [_apiManager removeFromFavorite:[object ID] withCompletion:^ {
      [weakSelf.favoriteButton setImage:[UIImage imageNamed:@"favorite"] forState:UIControlStateNormal];
    }];
  }

  else {
    [_apiManager addToFavorite:[object ID] withCompletion:^ {
      [weakSelf.favoriteButton setImage:[UIImage imageNamed:@"favorite_yellow"] forState:UIControlStateNormal];
    }];
  }
}

Actually, in this example isn't clear if there is a retain cycle. The retain cycle would happen if the completion block is declared as property of _apiManager . If it's just a block on the scope of a method (just a method parameter) then there is no retain cycle, however XCode is not smart enough to detect these cases and warnings you of a possible retain cycle.

Regarding to your question, it is just about the order, it warnings you on the first retain cycle, the second one doesn't matter since the block is already retaining self from the first block. If you fix the first warning by using __weak self, it will warning on the second block.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM