2

我是一个出生的 Obj-C 程序员,并且只生活在后 ARC 世界。不过,为了我自己的效率,我最近决定阅读 Apple 的Transitioning to ARC Release Notes。在ARC Introduces New Lifetime Qualifiers部分中,有一个标题为Use Lifetime Qualifiers to Avoid Strong Reference Cycles的小节,描述了潜在地使用限定符以避免潜在的保留循环的各种方法。

我的问题与最后两个例子有关。最后两个示例中的第一个使用了我经常使用的模式,以避免过早地从非主线程中释放 UIKit 对象:

MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyViewController = myController;
myController.completionHandler =  ^(NSInteger result) {
    [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
};

在上面的示例中,weakMyViewController对象是使用弱引用创建的,myController以便块引用weakMyViewController可以使用它,并且在块返回时,weakMyViewController可以安全地超出范围,而不会减少被引用的底层 UIKit 对象的引用计数。

不过,在下一个示例中,Apple 为“非平凡循环”显示了以下代码:

MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler =  ^(NSInteger result) {
    MyViewController *strongMyController = weakMyController;
    if (strongMyController) {
        // ...
        [strongMyController dismissViewControllerAnimated:YES completion:nil];
        // ...
    }
    else {
        // Probably nothing...
    }
};

在上面提供的“非平凡”示例中,相同的__weak限定符用于从块内引用 UIKit 对象,但随后代码会创建__strong对同一对象的本地隐式引用。然后对该本地__strong参考进行非零条件测试,然后对其进行操作。

我的两个问题是:

  1. Obj-C 程序员应该在什么考虑下实现第二种设计模式(而不是前者)?我不明白 Apple 关于“非平凡循环”的评论

  2. 不增加原始对象的保留计数的__strong引用如何?如果只是指向指向的基础对象的指针,那么强指针(即)不会增加基础对象(指向的对象)的保留计数吗?weakMyControllermyControllerweakMyControllermyControllerstringMyControllermyController

4

1 回答 1

3

关于您的第一个示例,您赋予块文字仅保留weak对指向的实例的引用的动机myController并不完全正确。weak引用不会阻止对象释放,弱引用的目的是防止强引用循环(也称为保留循环)。在这种情况下,强引用循环将通过myController保持对存储在 中的块的强引用来体现completionHandler,而块保持强引用回myController- 两者都不会被释放(completionHandler在未来某个时间没有取消设置属性)。因此,这里的动机与保持对象活着完全相反——它是允许myController当所有其他对它的引用不再存在时,正常解除分配。

第二个例子是第一个例子的扩展,但是通过将捕获的弱引用分配给块本地的强引用,我们可以确保只要控制器在块执行开始时仍然处于活动状态,它将保持活动状态直到结束块执行。由于强引用仅作用于块,它不会创建强引用循环。换句话说,strongMyController仅在块代码的范围内是本地的,并且不被块对象本身保留。

现在,为了解决您的具体问题:

  1. 当您想要确保块完成执行时,您将采用这种方法,并在其封闭范围内引用一个活动的非 nil 对象,如果该对象在块开始执行时是活动的。如果在块执行期间所有其他对对象的强引用可能会消失,您应该认真考虑使用它。
  2. 强引用确实增加了引用计数,这就是重点——当块代码的范围处于活动状态时,控制器将保持活动状态。这不会形成强引用循环,因为维护引用的不是块对象,而是块代码中使用的变量,该变量仅在块执行时存在。假设块不会继续执行到无穷大,那么循环将被打破。
于 2013-09-04T19:18:06.377 回答