Weak/Strong 嵌套块中的引用

Weak/Strong reference within nested blocks

我正在尝试找出嵌套块的 weakself/strongself 参考

有什么区别:

__weak __typeof__(self) weakSelf = self;

[self.networkCall_1 completionHandler:^(id response) {
    if(response) {
        [weakSelf.networkCall_2 completionHandler:^(id response2) {

        }];
    }
}];

和:

__weak __typeof__(self) weakSelf = self;

[self.networkCall_1 completionHandler:^(id response) {
    __typeof__(self) strongSelf = weakSelf;
    if(response) {
        [strongSelf.networkCall_2 completionHandler:^(id response2) {

        }];
    }
}];

我的理解是,如果我们不在内部块中使用 strongSelf,self 可能会被释放,因此 networkCall_2 可能为 nil,并且永远不会被调用。如果是这样,如果我不关心 networkCall_2 是否完成,我可以只使用 weakSelf 吗?另外,如果 networkCall_2 是 运行 并且 self 被释放会怎样?它会结束还是终止通话?谢谢!

(@trungduc 接近答案但不幸的是决定删除它。所以现在我可能无意中让你失去了你迄今为止唯一的答案我会看看我是否可以帮助你出。)

此答案仅适用于使用 ARC

What are the difference between:

可能令人惊讶的答案是 在这个特定示例中不是很多...

当 Objective-C 对对象进行方法调用时,它确保该对象在整个调用过程中都处于活动状态。所以在通话中:

[weakSelf.networkCall_2 completionHandler:^(id response2) {...}];

这是 shorthand(使用点表示法)用于:

[[weakSelf networkCall_2] completionHandler:^(id response2) {...}];

首先加载 weakSelf 并对结果持有强引用,将此引用称为 A。然后在 A 上调用 属性(方法)networkCall_2,并对其结果进行强引用,称为 B。此时,编译器可以自由删除强引用 A,因为它在此时未被使用。最后调用 B 上的方法 completionHandler:。在 returns 之后,可能在传递的完成块被调用之前,编译器可以随意删除强引用 B.

如果 AB 高于 nil 那么对它们的调用只是 return nil 并且什么也不会发生。

Note: your code is a little unusual, more common might be something like:

[weakSelf networkCall_2:<some argument> completionHandler:^(id response2) {...}];

that is networkCall_2:completionHandler: is a method on the object referenced by weakSelf. If this is what your actual code looks like then the above still applies and the compiler will hold a strong reference across the call to whatever weakSelf references.

现在转向:

__typeof__(self) strongSelf = weakSelf;
if(response) {
    [strongSelf.networkCall_2 completionHandler:^(id response2) {...}];

编译器首先加载 weakSelf 并在 strongSelf 中持有对它的强引用。然后在 strongSelf 上调用 属性(方法)networkCall_2,并对其结果进行强引用,称为 B。此时,编译器可以自由删除强引用 strongSelf,因为它在此时未被使用。等等

(注意:上面两种情况下的“自由丢弃”并不意味着编译器会立即丢弃它,它可能会推迟到 if 或块结束时才丢弃。)

注意到这两个描述的相似之处了吗?在这个特定的例子中,使用weakSelfstrongSelf之间确实没有区别。那么为什么有些代码使用 strongSelf 模式呢?考虑:

__typeof__(self) strongSelf = weakSelf;
if (strongSelf) // object still exists)
{
   // *all* three methods will be called
   [strongSelf method1];
   [strongSelf method2];
   [strongSelf method3];
}

对比:

[weakSelf method1]; // call method1 if weakSelf is not nil
[weakSelf method2]; // call method2 if weakSelf is *still* not nil
[weakSelf method3]; // call method3 if weakSelf is *still* not nil

使用上面的 strongSelf 模式可确保进行 0 次(如果 weakSelfnil)或 3 次方法调用。如果使用 weakSelf 模式,可能会调用 0、1、2 或 3 个方法。

您的特定示例具有相同的结果,因为 只有一个 使用 strongSelf/weakSelf,在上面的结果可能不同因为 多次 使用 strongSelf/weakSelf.

这给我们留下了您的问题:

Also, what happens if networkCall_2 is running, and self gets deallocated? Does it finish or terminate the call?

这个问题读起来好像 networkCall_2 是一种方法而不是 属性,请参阅上面的注释,我们将涵盖这两种情况:

  1. 如果您在这里指的是方法 networkCall_2self 那么如上所述 Objective-C 将在对任何对象的调用中保持强引用一个方法被调用,所以 self 不能在调用期间被释放。因此,活动呼叫永远不会因其 self 消失而终止。

  2. 如果你的networkCall_2确实是一个属性,那么weakSelf(上面的A)引用的对象将不会被释放在 属性 调用中,如 (1) 中所示。然而,当随后在 属性 调用 returned(上面的 B)的任何对象上调用 completionHandler: 方法时,可以在该调用中释放 A(除非该调用通过其他方式强烈引用 A)。

希望我正确理解了你的问题,如果是的话,我认为你的答案归结为知道:

An object on which a method (or property) is called will not be deallocated during that method (or property) call.

HTH