mikeash/MABlockClosure

Memory management with MABlockClosure under ARC?

tonyxiao opened this issue · 4 comments

What's the right memory management practice with BlockFptr and BlockFptrAuto when calling client is using ARC?

In particular, it appears that if look at the example code in the block

   int x = 42;
    void (*fptr)(void) = BlockFptrAuto(^{ NSLog(@"%d", x); });
    fptr(); // prints 42!

It seems that the moment we hit the end of the autorelease pool the fptr pointer will no longer be valid. So block needs to be explicitly declared and retained somewhere else. Is that the case?

just tested. Empirically the answer is yes, the block does need to be retained somehow. Here's a convenience function to simplify that task.

void *BlockFptrRetain(id block, id owner) {
    block = [block copy]; // Make sure block is on the heap first
    objc_setAssociatedObject(owner, &block, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return BlockFptr(block);
}

Just confirming, you're correct. As you can see, the implementation in BlockFptr doesn't retain the block, and there's nothing else going on behind the scenes to make it happen. My intended use case was for immediate callbacks, but if you want something longer term, your solution should work.

Revising my convenience function. it should actually be. Note the removed & symbol.

void *BlockFptrRetain(id block, id owner) {
    block = [block copy]; // Make sure block is on the heap first
    objc_setAssociatedObject(owner, block, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return BlockFptr(block);
}