Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Block implicitly retains 'self'; - but is it intended behaviour?

Yesterday my latest iOS build ran free of warnings on Xcode. Following an upgrade to Version 9.3 (9E145) overnight I got multiple warnings. When I tried self->score following an answer (1) to a similar question the warnings disappeared.

But in a more recent answer (2) to the same question the problem is solved by altering settings. Currently my settings for Apple LLVM 9.0 - Warnings -Objective C and ARC are

Implicit retain of ‘self’ within blocks Yes

But I don’t understand what Block implicitly retains 'self' means in the context of the code below so I can't say whether or not this behaviour is ‘intended’. Or whether I solved a problem or simply hid it. Or whether answer 1 would be better than answer 2.

Could someone kindly explain what Block implicitly retains 'self' means in this context ? Thanks.

score.alpha = 1.0;

if (sequenceState >= STATES_Count)
{
    [GraphicScore animateWithDuration:8.0f
                                delay:1.0f
                              options:UIViewAnimationOptionCurveEaseOut
                           animations:^{self->score.alpha = 0.0;} // animations:^{score.alpha = 0.0;}
                           completion:^(BOOL finished){ }];
}
[self addSubview:score];
like image 916
Greg Avatar asked Mar 30 '18 22:03

Greg


2 Answers

This warning about implicit references to self is useful because in the absence of that, when glancing at code it isn't always obvious which blocks have the risk of introducing strong reference cycles and which don't. By encouraging the programmer to make these self references explicit (such as is required in safe programming languages like Swift), you end up with code where you can plainly see whether a strong reference cycle is a potential issue or not.

So, I'd encourage you to leave the warning turned on but go ahead and make those implicit self references (the ivars) explicit with self-> or, if using properties, self., as advised by the first answer you referenced.

Then you can review those individual uses of self closures and make sure they don't introduce any real risk of strong reference cycles. And if they do, you can adopt the weakSelf or weakSelf/strongSelf patterns as appropriate.

like image 131
Rob Avatar answered Nov 19 '22 00:11

Rob


Given:

- (void)bobIsYourUncle {
   ^{score.alpha = 0.0;}();
}

Where score is an instance variable that instance variable is accessed via self. Because the block may be equeued somewhere and executed later, the block retains self when the block is created.

Because ivar access invisibly dereferences through self, that implicit retain is kinda not apparent in the code. The rather ugly suggestion by the compiler of adding self-> in front of the ivar makes it, at least, obvious that self is captured by the block.

So, yes, it is the correct behavior. And, yes, it is sometime desired. You could avoid it by grabbing the ivar's value before the block is created (in a local variable), but you must also know that doing so changes the time at which the ivar's value is obtained and that could cause a behavior change.

like image 3
bbum Avatar answered Nov 19 '22 00:11

bbum