我在块ivar中得到了一些具有明显引用循环的代码。以下代码导致引用循环,并且从未调用dealloc:
__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];
});
}
};
然而,如果我创建另一个__block
变量来保存对我的委托的引用,以便捕获块的作用域,那么引用周期就会消失:
__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];
});
}
};
只是想了解这里发生了什么。
我假设您在这里使用ARC。在使用ARC之前,您的第一个示例会很好。有了ARC,__block
的语义发生了变化。__block
声明现在被强捕获,而不是弱捕获。将第一个样本中的__block
替换为__weak
,所有操作都应按预期进行。
至于第二个例子的工作原理,您正在创建一个对委托的强引用,但您的委托没有对对象的引用。因此,没有循环,每个人都很快乐。
我建议阅读Mike Ash关于ARC引入的更改的文章,尤其是关于块捕获和__weak
的文章http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html