__ARC中ivar块中的块自参考循环



我在块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

最新更新