As you know, in ARC, __block variables of object pointer type used in a block are retained by the block. So take the following simplified example:
__block id foo = getObject();
void (^aBlock)() = ^ {
NSLog(@"%@", foo);
foo = getObject();
}
runBlockAsynchronouslyMultipleTimes(aBlock);
The object pointed to by foo is retained by the block, so that when the block is run (asynchronously), the object is still valid and can be printed. When we do the assignment within the block, ARC manages it like any other strong reference (the old value is released and the new value retained). (The assignment forces us to use __block in the first place.) And when the block is not needed anymore, ARC somehow releases its retained object pointed to by foo at that point (it is not leaked).
Okay, now suppose I want to do the same thing under MRC (why is not important; this is an question about the language). As you know, __block variables of object pointer type used in a block are NOT retained by the block in MRC. Which is fine; we'll manage it ourselves (this is MRC, after all). So the attempt looks like this:
__block id foo = [getObject() retain];
void (^aBlock)() = ^ {
NSLog(@"%@", foo);
[foo release];
foo = [getObject() retain];
}
runBlockAsynchronouslyMultipleTimes(aBlock);
// where to release foo?
Most of it is straight-forward -- the object is retained by us initially manually; inside the block, when we re-assign the pointer, we release and retain the new value as appropriate.
But then comes the problem: How do we release the object when the block is not needed anymore? Since we manually manage the memory, we should ideally manually release the object when the block is deallocated. But there doesn't seem to be an easy way to do so.
I could think of maybe one way: using associative references to tie the object to the block. But then to re-assign the associative reference inside the block, the block would need a reference to itself, so the block variable would also need to be __block and the block needs to be copied prior to setting the variable. Which is all very ugly. Or, we put the object inside a mutable container object that is then retained by the block; but that is ugly too.
runBlockAsynchronouslyMultipleTimes()is done dispatching youraBlockmultiple times, you would simply do one additional, final dispatch of a[foo release](using a dispatch barrier if your queue was concurrent, which it obviously is not in this case). Far simpler and more logical than associated references or anything like that. - RobrunBlockAsynchronouslyMultipleTimes()does internally. Sure, it may work in this particular case; but not in general -- what if in addition to being dispatched multiple times the block is also possibly stored somewhere else and possibly called later, in an unpredictable way? - newacct__blockfor the variable declaration, you're already engaged somewhat in what the block is doing internally, implicitly stating that the calling method is the owner, that the block will update it, but generally that the caller still assumes responsibility for clean up (hence if your blocks are running asynchronously, the caller will dispatch the clean up asynchronously, too). Personally, I find the whole notion of repeatedly updating a method's local variable asynchronously (beyond the life of the method) a little curious. - Rob