我是一个出生的 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
测试引用是否为非零条件,然后进行操作。
我的两个问题是:
Obj-C 程序员应该在什么考虑下实现第二种设计模式(相对于前者)?我不明白苹果关于“非平凡循环”的评论
__strong
怎么样?引用weakMyController
不增加原始myController
的保留计数目的?如果weakMyController
只是一个指向底层对象的指针myController
指向,强指针(即stringMyController
)不会增加底层对象(myController
指向的对象)的保留计数吗?
最佳答案
关于您的第一个示例,您认为 block 文字仅保留对 myController
指向的实例的弱
引用的动机并不完全正确。弱引用不会阻止对象释放,弱引用的目的是防止强引用循环(也称为保留循环)。在这种情况下,强引用循环将通过 myController
维护对存储在 completionHandler
中的 block 的强引用来体现,而该 block 又维护返回到 的强引用myController
- 两者都不会被释放(无需在将来的某个时间取消设置 completionHandler
属性)。因此,这里的动机与保持对象处于事件状态完全相反 - 它是为了允许 myController
当对它的所有其他引用不再存在时正常释放。
第二个示例是第一个示例的扩展,但是通过将捕获的弱引用分配给 block 本地的强引用,我们可以确保只要 Controller 在 block 执行开始时仍然处于事件状态,它就会保持事件状态直到 block 执行结束。由于强引用的范围仅限于 block ,因此它不会创建强引用循环。换句话说,strongMyController
仅在 block 代码的范围内是本地的,并且不被 block 对象本身保留。
现在,解决您的具体问题:
- 当您想要确保 block 通过对其封闭范围内的事件非零对象的引用来完成执行时,如果该对象在 block 开始执行时处于事件状态,则可以采用这种方法。如果在 block 执行期间对对象的所有其他强引用有可能消失,那么您应该认真考虑使用它。
- 强引用确实会增加引用计数,这就是要点 - 当 block 代码的范围处于事件状态时, Controller 将保持事件状态。这不会形成强引用循环,因为维护引用的不是 block 对象,而是 block 代码中使用的变量,该变量仅在 block 执行时存在。假设该 block 没有继续执行到无穷大,那么循环就会被打破。
关于ios - 重新捕获 block 内弱引用对象的强引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18621552/