ARC中的ivar块中的__block自引用循环

时间:2012-01-18 19:18:55

标签: objective-c memory-management automatic-ref-counting objective-c-blocks grand-central-dispatch

我在块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];
        });            
    }
};

只想了解这里发生了什么。

1 个答案:

答案 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

相关问题