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

Ash*_*row 9 memory-management objective-c grand-central-dispatch objective-c-blocks automatic-ref-counting

我在块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];
        });            
    }
};
Run Code Online (Sandbox Code Playgroud)

但是,如果我创建另一个__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];
        });            
    }
};
Run Code Online (Sandbox Code Playgroud)

只是想了解这里发生了什么.

Jos*_*erg 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