I've got some code with an apparent reference cycle in a block ivar. The following code causes a reference cycle and dealloc is never called:
__block MyViewController *blockSelf = self;
loggedInCallback = ^(BOOL success, NSError *error){
if (success)
{
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
{
[blockSelf.delegate loginDidFinish];
});
}
};
However, if I create another __block
variable to hold a reference to my delegate for the block's scope to capture, the reference cycle goes away:
__block id <MyViewControllerDelegate> blockDelegate = self.delegate;
loggedInCallback = ^(BOOL success, NSError *error){
if (success)
{
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
{
[blockDelegate loginDidFinish];
});
}
};
Just want to understand what's going on here.
I'm going to assume your'e using ARC here. Prior to ARC, your first example would work just fine. With ARC the semantics of __block
have changed. __block
declarations are now strongly captured, rather than weakly. Replace __block
with __weak
in your first sample and all should work as expected.
As for what the second example works, you are creating a strong reference to the delegate, but your that doesn't have a reference back to your object. Thus no cycle and everyone is happy.
I recommend reading Mike Ash's article on the changes introduced with ARC, especially around block capture and __weak
http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With