解除包含块的对象

时间:2013-06-23 10:53:13

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

首先(因为这个问题与内存管理有关),我不得不说我正在使用ARC。

我有一个对象(MyObject),它包含一个MyProcess对象数组。 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保持活动,因为该数组是唯一具有对该进程的引用的对象。当我在完成块上从数组中删除进程时,我认为该进程立即被解除了。然后,由于该进程包含块本身,所以当块仍在运行时块也会被解除锁定!

我希望这会导致问题,但我已经测试了这段代码,并且该块运行正常,直到最后。现在,有两个选择:要么我的推理是错误的,这个代码是完全安全的,或者我是对的(或者至少部分正确),这是不安全的,因为它只是有效。

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

1 个答案:

答案 0 :(得分:1)

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

@property (copy) MyCallbackBlock completionBlock;

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

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

从技术上讲,这可以归类为保留周期的一种形式,但由于其结构,它适用于你。

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


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