4

[block copy]执行后block();,我应该设置block=nil吗?或者 ARC 是否已经为我管理了这个,所以我不需要做任何事情?我对 ARC 如何在这里管理块引用有点困惑,我不确定将块设置为 nil 是否会破坏任何东西?

我有这样的东西。有什么想法吗?

typedef void (^C3Block)(void);    // declare block, no return, no args

// set flag to get _previewImage, then call the block
- (void)takePreviewImageFromBufferWithBlock:(C3Block)block {
    _takePreviewImageBlock = [block copy]; // save block ref for calling later
    _shouldTakePreviewImageFromBuffer = YES;
}

- (void)gotPreviewImageFromBuffer {
    _takePreviewImageBlock(); // calls the block
    _takePreviewImageBlock = nil; // <---- should I do this???
}
4

3 回答 3

5

我认为将其设置为 是个好主意,nil原因如下:

让我们调用这些方法所在的类ImageLoader。假设我有一个MyViewController对此有强引用的类ImageLoader(例如,它是一个实例变量),并将一个保留的块传递给它self(即MyViewController)。为什么保留self?好吧,你ImageLoader大概是异步工作的,所以,比如说,我希望我MyViewController能有足够长的时间来处理响应。

好的,所以我们有一个保留周期。MyViewController保留,ImageLoader保留块,保留MyViewController。但是,如果您只是nil在操作结束时将块变量放在 中ImageLoader,它将打破这个循环。否则这些对象将永远不会被释放。ImageLoader将块变量设置为操作完成时是有意义的,nil因为它不再“需要”它。

(您也可以争辩说,可以通过以不同方式安排保留来避免上述场景中的问题——不应该MyViewController保留。然后,在异步操作期间,仍然必须由正在进行的操作中的某些东西保留。仍然保留块保留。操作完成后,释放操作将释放所有内容,每个人都很高兴,无需将块变量设置为。)ImageLoaderImageLoaderImageLoaderMyViewControllerImageLoadernil

于 2013-02-01T10:11:50.127 回答
2

通常,将块 iVar 设置为 nil 是没有意义的,因为您很可能会通过连续-takePreviewImageFromBufferWithBlock:调用将其重置。从内存管理的角度来看,_takePreviewBlock它是一个 iVar,ARC 对它的管理将与任何其他 iVar 相同 - 当所有者类被释放时,它会在没有您交互的情况下正确释放。

于 2013-01-31T19:28:59.477 回答
2

如果_takePreviewImageBlock是具有属性的属性,则只要包含该属性的对象存在,ARC 就会保留它。
正如@Eugene 所提到的,它会在调用后重置takePreviewImageFromBufferWithBlock:

在了解了这种行为之后,您应该决定它是否适合您的设计。如果所有者将在之后立即解除分配,则无需自己将其属性为零。否则,如果此块不再与您的逻辑相关并且它将无缘无故地留在内存中,则您应该将其设为 nil。

于 2013-01-31T19:33:37.620 回答