ARC,通过捕获的自我在块和参考周期中的ivars

时间:2011-11-04 15:19:48

标签: objective-c ios ios5 objective-c-blocks automatic-ref-counting

我在纯iOS5 / ARC环境中工作,所以我可以根据需要使用__weak引用。在很多情况下我都会在块中引用ivars,最值得注意的是,移动视图的动画块,比如我的视图控制器类的属性。

我的问题:

  

在一个区块中最简单地使用ivars,我是否创建了一个参考周期?我是否需要每次都使用__weak self / strong self技术 我编写了一个操作包含对象的实例变量的块?

我一直在重新观看2011年WWDC会议#322(Objective-C深度进展),以了解从时间索引25:03开始的关于“通过捕获自我的参考周期”的3分钟段的细微差别。对我来说,这意味着任何块中ivars的使用都应该通过该段中描述的弱自我/强自我设置来保护。

以下是视图控制器上的示例方法,是我做过的典型动画。

在openIris块中,像我一样引用ivars“_topView”和“_bottomView”是错误的吗?

我是否应始终在块之前设置__weak引用自身,然后在块内强引用刚刚设置的弱引用,然后通过我块中的强引用访问ivars?

在WWDC会话中,我理解在块中引用ivars实际上是在创建对这些ivars挂起的隐含自我的引用。

对我而言,这意味着没有任何简单或无关紧要的情况,在没有弱/强舞的情况下访问块中的ivars是正确的,以确保没有循环。或者我是否正在阅读一个不适用于简单案例的角落案例,例如我的例子?

- (void)openIrisAnimated:(BOOL)animated
{
    if (_isIrisOpened) {
        NSLog(@"Asked to open an already open iris.");
        return; // Bail
    }

    // Put the common work into a block.
    // Note: “_topView” and “_bottomView” are the backing ivars of 
    // properties “topView” and “bottomView”
    void (^openIris)() = ^{
        _topView.frame     = CGRectMake(....);        
        _bottomView.frame  = CGRectMake(....);
    };

    // Now do the actual opening of the iris, whether animated or not:
    if (animated) {
        [UIView animateWithDuration:0.70f 
                         animations:^{
                             openIris();
                         }];
    }
    else {
        openIris();
    }

    _irisOpened = YES; // Because we have now just opened it
}

以下是我如何使用Session#322的指导重新编写openIris块块,但我只是想知道我所有类似的块是否需要这种弱/强参考舞以确保正确性和稳定性:

__weak MyClass *weakSelf = self;


void (^openIris)() = ^{
     MyClass *strongSelf = weakSelf;

     if (strongSelf) {        
        strongSelf.topView.frame     = CGRectMake(....);
        strongSelf.bottomView.frame  = CGRectMake(....);
     }
};

这实际上是必要的吗?

2 个答案:

答案 0 :(得分:21)

如果self继续持有对块的引用(或者self拥有的东西),那么这里只有一个循环。如果不是你就好了,因为它的生命周期不是由它保留的自我决定的。

所以在你的特定例子中,你似乎很清楚。动画块不需要参加弱/强自我舞蹈。

答案 1 :(得分:4)

担心的情况类似于addObserverForName:object:queue:usingBlock:。文档说:“该块由通知中心复制。”在ARC下,“复制”一词是一面红旗;现在你需要采取措施让你(来电者)不会泄漏。

编辑:此外,有时ARC本身会提醒您。 -[UIPageViewController setViewControllers:direction:animated:completion:]的完成块就是一个例子。我永远不会怀疑在这里使用self可能会导致保留周期,但ARC警告它会这样做,所以我做了弱强舞以防万一。