【问题标题】:Deallocking an object that contains a block解除锁定包含块的对象
【发布时间】:2013-06-23 10:53:13
【问题描述】:

首先(由于这个问题与内存管理有关),我不得不说我在 ARC 上运行。

我有一个包含 MyProcess 对象数组的对象 (MyObject)。 MyObject,在某个时刻,创建一个新的 MyProcess,将它添加到数组中,以块的形式给它一个完成处理程序,然后告诉进程开始。

MyProcess* newProcess = [MyProcess new];

[allProcessesArray addObject: newProcess];

newProcess.completionBlock = ^(MyProcess* process){
    [allProcessesArray removeObject: process];
    // Other things are done here
};

[newProcess start];

现在,在 MyProcess 方面,当 start 被调用时,MyProcess 在内部调用 threadedStart(在后台线程上运行),它完成它的工作,然后在完成时调用块:

- (void)threadedStart
{
    // Do something

    dispatch_async(dispatch_get_main_queue(), ^{ self.completionBlock(self); });
}

完成块是这样定义为MyProcess的接口中的一个属性的:

typedef void(^MyCallbackBlock)(MyProcess* process);
@property (strong) MyCallbackBlock completionBlock;

现在,MyProcess 仅在其生命周期内由 allProcessesArray 保持活动状态,因为该数组是唯一引用该进程的对象。当在完成块上我从数组中删除进程时,我认为进程会立即解除锁定。然后,由于进程包含块本身,因此块在它仍在运行时也会被解除锁定!

我预计这会导致问题,但我已经测试了这段代码,并且该块运行良好,直到结束。现在,有两种选择:要么我的推理是错误的,这段代码是完全安全的,要么我是对的(或至少部分正确),但这是不安全的,因为它只在某些时候有效。

基本上,我的问题是:这种回调块的方法安全吗?如果没有,您能提出一些不同的建议吗?

【问题讨论】:

    标签: objective-c cocoa memory-management objective-c-blocks dealloc


    【解决方案1】:

    对于您的块属性,它应该是copy,而不是strong。块应该总是被复制。

    @property (copy) MyCallbackBlock completionBlock;
    

    运行块是否会导致问题取决于运行的代码以及它使用的变量是如何定义的。

    在您的块内,由于myProcess 在块外定义的方式,它被保留在块内。因此,当您从数组中删除它时,它仍然会保留到块的末尾。

    从技术上讲,这可以归类为保留循环的一种形式,但由于其结构,它对您有用。

    块本身在运行时不能被“dealloc'd”。


    对于您更新的代码,该实例现在(可能是以前,我只是没看)由对块的调用保留(因为它是作为参数提供的)。同样,实例将一直保留到块执行结束。

    【讨论】:

    • 对不起,我刚刚注意到我弄乱了块内的变量名称。在第一个代码 sn-p 中,在块外使用“myProcess”,而在块内使用“process”变量。你能再检查一下代码吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    • 2019-12-07
    相关资源
    最近更新 更多