Wrapping Objective-C Delegates with Blocks, Part 1

Since adding blocks to Objective-C, Apple has designed more and more of their APIs to use them as the preferred callback mechanism over delegation—and for good reason. Blocks are (relatively) easy to use, lightweight, they play well with GCD, and most importantly for this post, they put the callback code right where it has the most context, thus making your code easier to read and reason about.

Many Apple APIs still use delegation, however, where blocks might make more sense; you can see this most often in classes designed before blocks became available. In this post and its follow-up, we’re going to look at two ways in which we can wrap an existing Apple API to use blocks instead of delegates.

UIAlertView will serve as our Guinea pig. It’s nearly ubiquitous in iOS apps, and it’s pretty easy to use. Nevertheless, it relies on a delegate to handle the user event of tapping one of its buttons, and this leads to clunky-feeling code:

Using the Apple-provided API, the UIAlertView is instantiated with its buttons and shown immediately—and when the user taps on one of those buttons, the code that handles the event is in a completely different method, perhaps separated by many lines, perhaps even so many that it’s offscreen.

Here, the code that handles the user event is right in the same place as the alert view’s initialization and display code itself. This results in much more elegant and readable code that reveals the programmer’s intent more obviously.

So let’s build this new APBAlertView and see how we are able to derive the benefits of using block-based callbacks.

I’ve created a project called AlertMe, which you can download from GitHub, and if you want, you can follow along by checking out the commit with the tag “Stock UIAlertView”. As you can see, the project is very simple: a UIButton triggers a UIAlertView, and tapping one of the buttons updates a label. Open up ViewControllerSpec.mm to see the tests that drive this feature (this project uses Cedar for testing). Amazingly, we won’t have to change them at all—APBAlertView will be a drop-in replacement for UIAlertView, and because our controller-level tests are behavioral, everything should work the same.

So we’ll create APBAlertView as a subclass of UIAlertView, and while we’re at it, we’ll create a spec file. APBAlertView will act as it’s own delegate, and it will handle the delegate events by calling the appropriate completion blocks, as the tests imply: