重新获得对块内弱参考对象的强引用

时间:2013-09-04 18:49:50

标签: ios objective-c c macos automatic-ref-counting

我是一名出生的Obj-C程序员,并且只生活在ARC后世界。不过,就我自己的功效而言,我最近决定通过Apple的 Transitioning to ARC Release Notes 。在 ARC Introduces New Lifetime Qualifiers 部分中,有一个标题为使用终身限定符以避免强引用周期的小节,其中描述了使用潜在限定符的各种方法,以避免潜在的保留周期。

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

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

在上面的示例中,使用对weakMyViewController的弱引用创建myController对象,以便引用weakMyViewController的块可以使用它,并在返回块时weakMyViewController 1}}可以安全地超出范围而不减少被引用的底层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. __strongweakMyController的引用如何不增加原始myController对象的保留计数?如果weakMyController只是指向myController指向的基础对象的指针,则强指针(即stringMyController)不会增加底层对象({myController的保留计数{1}}指向)?

1 个答案:

答案 0 :(得分:3)

关于你的第一个例子,你认为拥有块文字的动机只保留对weak指向的实例的myController引用并不完全正确。 weak引用不会阻止对象解除分配,弱引用的目的是阻止强引用循环(也称为保留循环)。在这种情况下,强引用周期将表现为myController保持对completionHandler中存储的块的强引用,而块保持强引用回myController - 两者都不会被取消分配(未来某个时候不取消设置completionHandler属性)。因此,这里的动机与保持对象存活完全相反 - 允许myController在其所有其他引用都不存在时正常解除分配。

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

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

  1. 当您希望确保块完成执行时,如果该块在块开始执行时该对象处于活动状态,则可以使用此方法从其封闭范围引用实时非零对象。如果在执行块期间对对象的所有其他强引用都可能消失,则应认真考虑使用它。
  2. 强引用肯定会增加引用计数,并且是重点 - 当块代码的作用域处于活动状态时,控制器将保持活动状态。这不会形成强引用循环,因为它不是维护引用的块对象,而是块代码中使用的变量,仅在块执行时存在。假设块没有继续执行到无穷大,那么循环就会被打破。
相关问题