I am working on this code, which does some lengthy asyncronous operation on the net and when it finishes it triggers a completion block where some test is executed and if a variable get a certain value another lengthy operation should start immediately:
-(void) performOperation
{
void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request){
int variable=0;
// Do completion operation A
//...
//...
// Do completion operation B
//Get the variable value
if(variable>0){
[self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock];
}
};
//Perform the lenhgty operation with the above completionBlock
[self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock];
}
-(void) doLengthyAsynchronousOperationWithCompletionBlock: completionBlock
{
//Do some lengthy asynchronous stuff
}
With this code I get this warning from the compiler:
WARNING: Block pointer variable 'completionBlock' is uninitialized when caputerd by the block
I changed:
void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)
in:
__block void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)
but I get this other warning:
WARNING 2: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle
How can I fix this?
Thanks
Nicola
This happens because block variables initialized to a recursive block need
__block
storage.__block
, in which case they are passed as reference.__block
, the block will be created with a reference to the variable instead. Then the variable will be initialized to the created block, and the block will be ready to use.This happens because a block variable is a strong reference to the block, and the block is itself referencing the variable (because as we saw before, the variable has a
__block
so it is referenced instead copied).So we need
The name
doLengthyAsynchronousOperationWithCompletionBlock
suggests that the method may outlive the method scope where the block is created. Given that the compiler doesn't copy a block passed as an argument, it's responsibility of this method to copy this block. If we are using this block with block aware code (eg:dispatch_async()
), this happens automatically.Had we been assigning this block to an instance variable, we would need a
@property(copy)
and a weak reference to self inside the block, but this is not the case, so we just use self.