ARC, Blocks and Retain Cycles

Hunter picture Hunter · Oct 14, 2011 · Viewed 12.4k times · Source

Working on an iOS project that targets 4.0 and 5.0, using ARC.

Running into an issue related to blocks, ARC and referencing an object from outside the block. Here's some code:

 __block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
   [operation setCompletionBlock:^ {
       if ([operation isCancelled]) {
           return;
       }

... do stuff ...

operation = nil;
}];

In this case, the compiler gives a warning that using 'operation' in the block is going to lead to a retain cycle. Under ARC, __block now retains the variable.

If I add __unsafe_unretained, the compiler releases the object immediately, so obviously that won't work.

I'm targeting 4.0 so I can't use __weak.

I tried doing something like this:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation;

but while weakOperation isn't nil, none of it's properties are populated when inside the block.

What's the best way to handle this situation given the project constraints listed above?

Answer

Jeremy W. Sherman picture Jeremy W. Sherman · Oct 14, 2011

Assuming progress guarantees, a retain cycle might be exactly what you want. You explicitly break the retain cycle at the end of the block, so it's not a permanent retain cycle: when the block is called, the cycle is broken.

If you have something else keeping the operation around, though, you can store a reference into either a __weak or __unsafe_unretained variable and then use that from within your block. There's no need to __block-qualify the variable unless you for some reason need to change the variable's binding during the block; since you don't have a retain cycle to break any more, you shouldn't need to assign anything to the weak variable.