Reputation: 8412
I have a method similar to this:
- (void)loadStoreWithCompletion:(CompletionBlock)loadCompletion
{
dispatch_queue_t loadQueue = dispatch_queue_create("loadQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(loadQueue, ^{
// ... Do background stuff ...
});
dispatch_async(loadQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
loadCompletion();
});
});
dispatch_release(loadQueue);
}
Do I need to copy the loadCompletion
block because it only might get called when the caller of this method no longer exists, or is it fine like this?
Upvotes: 0
Views: 133
Reputation: 133567
Blocks are allocated on the stack by the caller, this means that once out of scope, an invocation leads to an error.
You should always copy them to the heap when you intend to use them later (as in a callback which happens asynchronously), you can do it either
[block copy]
copy
Mind that retaining them or releasing them doesn't always work because they might be on stack.
Upvotes: 0
Reputation: 90531
You can rely on dispatch_async()
doing the right thing with the blocks that are passed to it directly. It's also the case that when a block is copied, it copies any blocks which are captured by it. Since loadCompletion
is referenced by the inner block and it is not declared with __block
, it is captured. In other words, you're fine.
Upvotes: 3
Reputation: 29886
The act of referencing the block parameter inside another block will cause it to be copied to the heap implicitly, so you don't need to explicitly do so.
Upvotes: 3
Reputation: 11834
It's fine like this. But you should make 1 change in your code:
dispatch_async(loadQueue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
if (loadCompletion) {
loadCompletion();
}
});
});
You can test it yourself. If you call the method without any parameters ([instance loadStoreWithCompletion:nil];
), in your version of the code the app would crash upon invoking the completion handler. The block check will prevent any crashes in case the block does not exist (anymore).
Upvotes: 0