ios - 重新捕获 block 内弱引用对象的强引用

标签 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 的弱引用创建的这样 block 引用 weakMyViewController可以使用它,并且在返回 block 后,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限定符用于从 block 内引用 UIKit 对象,但随后代码会创建本地隐式 __strong对同一个对象的引用。然后那个本地__strong测试引用是否为非零条件,然后进行操作。

我的两个问题是:

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

  2. __strong 怎么样?引用weakMyController不增加原始 myController 的保留计数目的?如果weakMyController只是一个指向底层对象的指针 myController指向,强指针(即 stringMyController )不会增加底层对象( myController 指向的对象)的保留计数吗?

最佳答案

关于您的第一个示例,您认为 block 文字仅保留对 myController 指向的实例的引用的动机并不完全正确。弱引用不会阻止对象释放,弱引用的目的是防止强引用循环(也称为保留循环)。在这种情况下,强引用循环将通过 myController 维护对存储在 completionHandler 中的 block 的强引用来体现,而该 block 又维护返回到 的强引用myController - 两者都不会被释放(无需在将来的某个时间取消设置 completionHandler 属性)。因此,这里的动机与保持对象处于事件状态完全相反 - 它是为了允许 myController 当对它的所有其他引用不再存在时正常释放。

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

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

  1. 当您想要确保 block 通过对其封闭范围内的事件非零对象的引用来完成执行时,如果该对象在 block 开始执行时处于事件状态,则可以采用这种方法。如果在 block 执行期间对对象的所有其他强引用有可能消失,那么您应该认真考虑使用它。
  2. 强引用确实会增加引用计数,这就是要点 - 当 block 代码的范围处于事件状态时, Controller 将保持事件状态。这不会形成强引用循环,因为维护引用的不是 block 对象,而是 block 代码中使用的变量,该变量仅在 block 执行时存在。假设该 block 没有继续执行到无穷大,那么循环就会被打破。

关于ios - 重新捕获 block 内弱引用对象的强引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18621552/

相关文章:

ios - Apple Watch Table - 前 4 行未出现

iphone - 导航栏中的 UIButton,如 Tweetbot

c - struct 数组按值传递,而不是按引用传递

c - 浮点文字 “.1” 与 C 中的 “0.1” 相同吗?

iOS Swift - 二维码

ios - 同时选择另一个表格 View 单元格时如何取消选择表格 View 单元格?

ios - 用于测试是否正在构建应用程序扩展的预处理器宏是什么?

ios - 使用 interactivePopGestureRecognizer 交互式过渡同步另一个动画

objective-c - 将可选的 JSON 从 react-native 传递给 Swift

C11 : Using `_Generic()` (or something) for types themselves (not instances of types)?