Purposely Create Retain Cycle (Objective C without GC)

automatic-ref-counting, memory-management, objective-c, retain-cycle

Solution

Sure. It's actually not all that uncommon, though you may not realize it.

For example, let's assume that my controller is making a network request, and I really need to make sure I handle the response, even if the user has navigated away from that controller.

I might do something like this:

- (void)doNetworkThing {
    __block MyController *blockSelf = self;

    NSURLRequest *request = // some request
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:
      ^(NSURLResponse *response, NSData *data, NSError *error) {
          // Handle the response here
          [blockSelf doThingWithResponse:response];
      }];
}

This introduces a trivial retain cycle where `self` has caused itself to be retained by assigning itself to the strong pointer `blockSelf`. Until `blockSelf` goes out of scope, self will not be deallocated.

Note that often, you would use a weak pointer in this situation. But if you really need the controller to be around to handle it, using a strong pointer works too. As soon as the handler block is deallocated, its reference to `blockSelf` will go away. Since the the stack reference to `blockSelf` is also gone self will then be deallocated if nobody else is holding on to it.

So basically, `blockSelf` caused a temporary retain cycle, which was useful in ensuring that deallocation could not happen until the request finished. Because ARC automatically cleans up the retain counts when the __block variable goes out of scope, it doesn't look much like a retain cycle. But nevertheless, that's what it is.

Problem

Is there ever a case where purposely creating a retain cycle to prevent deallocation, then cleaning it up later, is the best solution to a problem? If so, are there examples of this in the Cocoa Touch or NextStep frameworks? I intend this question to be specific to Objective C with ARC since Objective C with GC or other languages with GC may behave differently.

Original source