One of the things that has annoyed me while developing my iPhone game “Wordly” are dialogs that appear modal to the user, but are non-blocking from the programmer perspective. For example, let’s take UIAlertView
.
You tell a UIAlertView
to show itself and the user sees a modal dialog, but the code after your show
message keeps executing, before the user even clicks anything. The way to find out which button the user clicked is via a callback; the UIAlertView
calls the alertView:clickedButtonAtIndex:
method of the delegate object (an object that conforms to the UIAlertViewDelegate
protocol) that you supply.
So using the calling object as the delegate, it looks something like this:
A few things bother me about this style:
- Displaying a modal dialog and then reacting to the choice is conceptually a simple, sequential process, but you end up splitting your steps between two methods. The first method doesn’t even mention the name of the second method, so for programmers who are unfamiliar with Cocoa or just forgetful of what the magic method is in
UIAlertViewDelegate
, it’s not immediately clear how the code flows.
- To decide how to handle a button press, you have to match against a button index or a button title that you used in the other method. This is in my mind a violation of the DRY principle and it’s error prone.
- If your class is the delegate for a bunch of dialogs, stuff starts to get messy pretty quickly, as your method needs to distinguish between different dialogs by looking at the alert view’s tag or otherwise inspecting it.
Basically, it’s not as readable as I would like. It seems I am not alone:
Interestingly, the authors of the latter two blog posts also develop solutions that are similar to my first solution below. I’ve not yet found anything that looks like the second solution that I discuss below.
My first idea for how to make things more intuitive was to create a new class called ModalAlertView
. Basically it just polls in a while loop, until the callback gets called. NSRunLoop
‘s runUntilDate
method is used in the while loop to let the event loop process events – here’s the relevant part of the code:
Now you can use this modal dialog something like this:
This seems to work pretty well, but it still bothers me. Polling is wasteful and we’re talking about mobile devices here, so we’re wasting processor time and battery life and when we have multitasking in iPhone OS 4, this will be wasting time that other processes could be using. The API also seems to really be pushing the developer in the direction of having non-blocking code and this approach kind of subverts that. I’d rather not go against the grain.
So I searched for another solution. For a while I thought the problem I was trying to solve was how to create a modal dialog. But then it dawned on me that the real problem was that I wanted a more intuitive way to create and react to dialogs. Making the dialog modal was one way to make things more intuitive to my sequential brain, but there was perhaps another way.
The other way was to create a class that displays the dialog and then acts as the delegate for that dialog, doing dispatching to whatever methods the caller specifies for the buttons, thereby relieving the caller of the responsibility of doing the dispatching. The caller uses the new API like this:
Concise. Simple. And it can be implemented with pretty simple Objective-C, without funky polling and run loops. Here’s what the implementation looks like:
Nothing too hairy in there, that I can see.
It gives you a simple API that lets you create buttons and link them to specific handler methods. You don’t even need to worry about releasing the dialog object as it adds itself to the autorelease pool after the callback fires.
Objective-C afficionados, please send me any suggested improvements…