Reputation: 12421
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.
Upvotes: 9
Views: 2793
Reputation: 28688
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
Upvotes: 16