如您所知,在 ARC 中,__block
块中使用的对象指针类型的变量由块保留。因此,采取以下简化示例:
__block id foo = getObject();
void (^aBlock)() = ^ {
NSLog(@"%@", foo);
foo = getObject();
}
runBlockAsynchronouslyMultipleTimes(aBlock);
所指向的对象foo
由块保留,这样当块运行(异步)时,该对象仍然有效并且可以打印。当我们在块内进行赋值时,ARC 像任何其他强引用一样管理它(旧值被释放,新值被保留)。(分配迫使我们首先使用__block
。)当不再需要该块时,ARC 以某种方式释放其foo
在该点指向的保留对象(它没有泄漏)。
好的,现在假设我想在 MRC 下做同样的事情(为什么不重要;这是关于语言的问题)。如您所知,__block
块中使用的对象指针类型的变量不会被 MRC 中的块保留。这很好;我们将自己管理它(毕竟这是 MRC)。所以尝试看起来像这样:
__block id foo = [getObject() retain];
void (^aBlock)() = ^ {
NSLog(@"%@", foo);
[foo release];
foo = [getObject() retain];
}
runBlockAsynchronouslyMultipleTimes(aBlock);
// where to release foo?
大部分都是直截了当的——对象最初是由我们手动保留的;在块内部,当我们重新分配指针时,我们会酌情释放并保留新值。
但随之而来的问题是:当块不再需要时,我们如何释放对象?由于我们手动管理内存,理想情况下我们应该在块被释放时手动释放对象。但似乎没有一个简单的方法可以做到这一点。
我可能会想到一种方法:使用关联引用将对象绑定到块。但是然后要重新分配块内的关联引用,块需要对自身的引用,因此块变量也需要,__block
并且在设置变量之前需要复制块。这一切都很丑陋。或者,我们将对象放在一个可变的容器对象中,然后由块保留;但这也很丑陋。