beatjunky99
beatjunky99

Reputation: 149

Call Block_Release inside block to be released

Is it possible to release a block inside itself? For the compiler it's fine, but I'm not sure if at runtime it will crash, since it releases memory that is executed at the same time.

cancel_block_t someFunction(/*args*/){
    __block BOOL canceled = NO;
    __block cancel_block_t cancel_block = Block_copy(^{
        canceled = YES;
        Block_Release(cancel_block); //<-- can I do this?
        cancel_block = NULL; //<-- can I do this?
    });
    // […]
    return cancel_block;
}

Would this approach be more safe?

 cancel_block_t someFunction(/*args*/){
    __block BOOL canceled = NO;
    __block cancel_block_t cancel_block = Block_copy(^{
        canceled = YES;
        dispatch_async(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),^{
            Block_Release(cancel_block);
            cancel_block = NULL;
        });
    });
    // […]
    return cancel_block;
}

Thanks for help!

Edit #1: corrected return type of function.

Upvotes: 0

Views: 252

Answers (1)

Ken Thomases
Ken Thomases

Reputation: 90571

Is this non-ARC code? ARC will automatically copy, retain, and release blocks.

Anyway, this is not safe, at least not always. I've seen crashes for similar behavior. The issue is that the reference to the __block variable is within the same block object that Block_release() may deallocate. So, trying to set the variable can access memory after it's been freed (and maybe reused).

About your function:

1) Why does it return a pointer to a block type? It would be more normal for the function to just return the block type (which is already a reference). That is, someFunction() should have a return type of cancel_block_t, not cancel_block_t*. Anyway, it's not safe to take the address of a __block variable, since such a variable can change location. It starts life on the stack but gets moved to the heap.

2) The normal semantics for a function that returns a block would be to return an autoreleased object. So, someFunction() should just return [cancel_block autorelease]; (given that it's already been copied). The caller is responsible for retaining it if it wants to keep it beyond the current scope or autorelease pool. If it's submitted to a function (e.g. dispatch_async()), then that function is responsible for retaining it. In other words, the memory management semantics are the same as any other object. The block should not try to release itself.

Upvotes: 1

Related Questions