繁体   English   中英

在iOS上使用带有ARC的块时,确保对象存在并且不会泄漏的正确方法是什么?

[英]What is the correct way to be sure that the object will be there and it won't leak while using blocks with ARC on iOS?

以下哪个代码段是正确的?

“我”的正确定义:

  • 它不应具有保留周期,因此也不应泄漏。
  • 它必须保证method2和method3的运行。 因此,块中的MyObject变量绝不能为nil。(在__weak定义中可能会发生...)(我不想检查它是否为nil以防止崩溃。我一直希望它为非nil)。

更新:(其他信息)仪器工具确实显示出奇怪的泄漏,直到我将__block替换为__weak为止。 但是,此后,我记得__weak引用可能随时消失。 我必须确保它也不会消失和泄漏。 我没有计时器。 当它观察到特定的NSNotification时,在主线程上调用此someMethod。

@implementation MyObject...

-(void)someMethod{
    AnotherObject *abc=[[AnotherObject alloc]init];
    __weak MyObject *weakSelf=self;
    abc.onSuccess=^{
         __strong MyObject * strongSelf = weakSelf;
        [strongSelf method2];
        [strongSelf method3];
    }

}

要么

@implementation MyObject...

-(void)someMethod{
    AnotherObject *abc=[[AnotherObject alloc]init];
    __block MyObject *blockSelf=self;
    abc.onSuccess=^{
        [blockSelf method2];
        [blockSelf method3];

        blockSelf=nil;
    }

}

更新2:实际代码,如果我不使用__weak总是会泄漏:

    __block RButton *_self=self;
    _aimageView.onSuccess=^(void){
        [_self.headerLabel setText:[_self.book title]];
        _self = nil;
    };

区块可以提及self而不会引起任何泄漏。 因此,要做的第一件事就是指定情况。 您为什么认为积木泄漏? 你检查了吗 如果没有理由担心,那就没有必要担心了。

如果该区块的self提及确实导致泄漏,那么您可以采取的步骤取决于发生这种情况的原因。 但是您还没有向我们展示。 例如,提到self的调度计时器块可能会导致保留周期,但是使用计时器完成操作后,您可以中断该周期,因此不会发生泄漏。

因此,最好理解一个特定的保留周期,而不是不必进行防御性编程。

编辑(针对您的评论) 我书中的这段代码演示了在NSNotification观察者情况下处理内存管理的各种方法: 单击此处

我已经在“更新2”中查看了您的实际代码,但是缺少很多信息。 例如, _aimageView是实例变量吗? 局部变量? 要不然是啥? 是什么导致此onSuccess被调用?

如果_aimageView是局部变量,那么我看不到保留周期的证据。

我的第一个想法是我不明白为什么要保证在此示例中运行块体内的代码。 看起来其中的代码只是在更新一些UI元素。 好吧,如果UI不再显示(例如,当前对象可能没有通过此块对其进行引用),那么更新UI元素的意义何在?

重要的是要知道是什么导致了onSuccess调用,因为不同类型的回调需要不同的内存管理架构。 例如,如果响应某个触摸或类似事件触发了该块,则可能是self指向的对象(可能是某种视图或视图控制器)必须仍然存在,以便事件发生。 如果真是这样,那么__weak会做您想要的。

基本上,通过命名这些变量,可以合理地得出以下结论: _aimageView可能是当前对象在概念上“拥有”的图像视图,而onSuccess是该图像视图“拥有”的完成块。 除非某些其他对象对其有很强的引用,否则“拥有”对象的生存期仅限于其“拥有”对象的生存期。 因此,该块将不会超出图像视图的寿命,而该图像视图也将不会超出当前对象的寿命。

您担心的唯一方法(当块运行时,由self指向的对象被释放)可能是其他某个对象存储了对_aimageView或对该块的强引用。 对于该块,一个对象的“成功块”不太可能与其他对象一起存储。 对于图像视图,如果图像视图“属于”当前对象,则不太可能。 (可以想象,它可能存储在自动释放池中或其他东西中;但是自动释放池除了释放之外不会调用其中的东西,所以这不是问题。)

我能想到的唯一例外是,图像视图是由待处理的网络操作还是其他方法保留,完成onSucess调用onSucess块。 但是,如果是这种情况,我想说将一个对象同时用作视图和网络操作是不好的设计。 相反,在那种情况下,应该有一个专用的网络操作对象,它是一个局部变量,并在其上设置一个完成块(例如,将图像存储在图像视图中,设置标签等),开始操作,不需要存储操作。 然后,该块可以强烈地引用self ,但是没有保留周期。

总而言之,该块(以及拥有它的图像视图)应根据谁使该块保持活动 (即谁保留它,谁对其保持强烈引用)而属于以下两种类别之一:

  • 如果self使它保持活动状态:例如,一个视图控制器使它的视图和子视图保持活动状态。 在这种情况下,使用__weak是安全的,因为该块在self生命之外不存在。

  • 如果有人让它保持活动状态:例如警报视图,您只需创建并显示它; 系统随后将其保留在屏幕上。 在这种情况下, self不应(也不需要)对其进行引用,并且可以在块中强烈引用self 它不会导致保留周期。

尽量避免self和他人使自己活着的情况。

因为您需要保证method2method3被执行,所以您需要由self引用的对象保持活动状态。 为此,请遵循标准模式:在需要时始终保持强烈参考。 您的第二个代码片段将执行此操作。

参考周期并不是天生的坏,而是非托管周期。 在这里,您先做一个循环然后再打破它,所以没有问题。

(请注意,您可以发送一条消息到nil ,如果strongSelfnil ,第一个代码片段将不会崩溃-它只会做任何事情。)

-(void)someMethod{
    AnotherObject *abc=[[AnotherObject alloc]init];
    abc.onSuccess=^{
        [self method2];
        [self method3];
    }
}

这将使。 它不会导致保留周期。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM