1

Should all passed block handlers be nil out when the class is done running? What happen if none of the blocks are nil'ed at all?

For example, the following code:

- (void)runWithCompletionHandler:(void (^)(id results))completion
                  failureHandler:(void (^)(NSError *))failure {

    self.completionHandler = completion;
    self.failureHandler = failure;

    [self run];
}

// Run will be overridden by subclass and 
// finishWithResults will be called when subclass is done
- (void)run {
    [self finishWithResults:nil];
}

- (void)finishWithResults:(id)results {
    if (self.completionHandler) {
        self.completionHandler(results);
        // Question: Is it necessary to nil out the completion handler?
        self.completionHandler = nil;
    }

    // Question: Should failure handler be nil out here as well?
}

- (void)finishWithErrors:(IHRCarPlayContent *)errors {
    if (self.failureHandler) {
        self.failureHandler(errors);
        self.failureHandler = nil;
    }

    // Question: Should completion handler be nil out here as well?
}
Boon
  • 40,656
  • 60
  • 209
  • 315
  • If you're using ARC then your blocks will be nil'd out whenever there is no longer a reference to them. – CrimsonChris May 31 '14 at 03:59
  • @GregParker Why wouldn't they? The blocks in my apps are released when remove the last reference to them. I'm suggesting to the OP that if the object that contains the posted code is released then the blocks will be released as well if it is the only object that is keeping a reference to them. – CrimsonChris May 31 '14 at 04:29
  • 1
    @CrimsonChris, in a phrase: retain cycles. – Ken Thomases May 31 '14 at 08:21
  • You would only need to nil out the block if you introduced a retain cycle with it. – CrimsonChris May 31 '14 at 18:26
  • @CrimsonChris, since the blocks are passed in from outside of this code, how is this code supposed to know if the block introduces a retain cycle? It can't, so it must assume it might. – Ken Thomases Jun 01 '14 at 13:28

1 Answers1

5

It's usually a good idea, because it means that any objects captured by the completion handler will be released. This helps reduce memory usage, and in particular helps break retain cycles.

Catfish_Man
  • 41,261
  • 11
  • 67
  • 84
  • 1
    In general I'd say you should nil out any resource you're certain that you're done with. – Nicholas Hart May 31 '14 at 03:59
  • 1
    In the case above with a success handler and a failure handler, you would want to erase both after either one is called. – Greg Parker May 31 '14 at 04:15
  • When the object that contains the handlers are released, will the blocks be automatically released as well? – Boon May 31 '14 at 05:05
  • 2
    @Boon, if the blocks hold a reference to the object that holds them (the `self` in the given code) or hold references to objects that in turn hold references to this object (etc.), then there's a retain cycle. If nothing breaks the cycle, then none of those objects will be deallocated. You're right that **if** this object is deallocated, it will release the references it holds on those blocks. Clearing out the block references may be a prerequisite for this object being deallocated, though. – Ken Thomases May 31 '14 at 08:21