我在块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];
});
}
};
只想了解这里发生了什么。
答案 0 :(得分:16)
我将假设你在这里使用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