Stop Using Success/Failure Blocks

I‘m not entirely sure where this first started, but a pattern that you seen a lot in third party Objective-C libraries is using separate success/failure blocks for callback on asynchronous API. It’s surprising that is has caught on for a couple of reasons. The first is that most good Objective-C developers seem to want to do things the “the Apple way,” and Apple doesn’t use this pattern anywhere. The other reason is that the problem with it isn’t an edge case, but something you’ll come up against whenever you use the pattern.

As an example, here‘s a piece of code that uses separate success/failure blocks:

[object doSomethingWithSuccess:^(NSData *data) {
    [self.activityIndicator stopAnimating];
    // Do something with the data
} failure:^(NSError *error) {
    [self.activityIndicator stopAnimating];
    // Do something with the error
}];

And here’s how I’d write it:

[object doSomethingWithCompletion:^(NSData *data, NSError *error) {
    [self.activityIndicator stopAnimating];
    if (data != nil) {
        // Do something with the data
    } else {
        // Do something with the error
    }
}];

If you go and look at any Apple API that uses a completion handler, you’ll see they follow the second pattern. Using separate success/failure blocks forces you to repeat code, because cleanup code is usually independent of success or failure. Don’t do that.

[Update 4:28 PM: As Tim pointed out in the comments, the success flag I had on my callback block was superfluous, so I removed it from the example.]

Collin Donnell @collin