Reputation: 7959
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?
Upvotes: 0
Views: 752
Reputation: 2052
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.
Upvotes: 0
Reputation: 11724
_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];
}];
}
}
Upvotes: 3