嵌套块中的弱/强引用

时间:2017-12-12 01:14:02

标签: objective-c objective-c-blocks

我正在试图弄清楚嵌套块的弱自己/自我引用

有什么区别:

__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被取消分配,会发生什么?是完成还是终止通话?谢谢!

1 个答案:

答案 0 :(得分:2)

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

此答案仅适用于使用ARC

  

有什么区别:

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

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

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

是:用点符号表示:

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

首先加载weakSelf并对结果保持强引用,调用此引用A。然后在networkCall_2上调用属性(方法)A,并对其结果进行强引用,调用此B。此时,编译器可以自由删除强引用A,因为它未通过此点使用。最后调用completionHandler:上方法B的调用。在返回之后,可能在调用传递的完成块之前,编译器可以放弃强引用B

如果AB高于nil,那么对它们的调用只会返回nil并且没有任何进展。

  

注意:您的代码有点不寻常,更常见的可能是:

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

networkCall_2:completionHandler:weakSelf引用的对象的方法。如果这是您的实际代码的样子,那么上述内容仍然适用,并且编译器将在调用任何weakSelf引用时保留强引用。

现在转到:

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

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

(注意:&#34;可以自由删除&#34;在上述两种情况下并不意味着编译器会立即删除它,它可能会推迟到if或块结束。 )

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

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

VS

[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

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

  

此外,如果networkCall_2正在运行,并且self被取消分配,会发生什么?完成或终止通话吗?

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

  1. 如果您指的是方法self的{​​{1}},那么如上所述,Objective-C将对调用方法的任何对象的调用保持强引用,所以networkCall_2在通话期间无法解除分配。因此,由于self消失,所以永远不会终止有效通话。

  2. 如果self确实是显示的属性,那么networkCall_2引用的对象(上面的weakSelf)将不会在属性调用中被释放,如( 1)。但是,当然后在属性调用返回的任何对象(上面的A)上调用completionHandler:方法时,可以在该调用中释放B(除非该调用具有对{{的强引用) 1}}通过其他方式)。

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

      

    在该方法(或属性)调用期间,不会释放调用方法(或属性)的对象。

    HTH