//
you're reading...

Programming

Painless UIAlertView

Using UIAlertView can be quite painful. Here it is, a rather short-lived object that typically doesn’t last a minute (that is, alert view objects gets discarded after they’re dismissed) but then it demands a delegate if you want to get any data out of it – to know what button that the user selected to dismiss the alert view. You have the alert view object created and shown in one method and then you have its delegate methods, located half a source file away. Then you’ll need to carry some state from the creator method to the delegate method. Typically you use the tag property inherited from UIView and have an anonymous enum to identify which part of the code that created this particular UIAlertView instance. When the UIAlertView gets dismissed, your delegate method reads this tag and do a switch to link this back to the logic which displayed this alert in the first place and then takes action.

Being forced to use a delegate for a transient object like UIAlertView makes code that is supposed to be straightforward – ask the user something and then takes action on it, but never really re-use the alert view again – to be unnecessarily complicated. You’ll need to split a simple logic that can be neatly contained in one method into at least two methods: one that creates the alert view and another that implements the alert view’s delegate. Worse the delegate method containing the latter half of the logic also contains similar logic from other methods, a classic case of spaghetti code.

reduce programming painThis may be understandable since UIAlertView was engineered before closures came to Objective-C. However it’s been more than two versions of iOS since blocks were available and we are still forced to deal with this messy alert view delegate without an better alternatives.

Well, not anymore! Introducing BSAlertViewDelegateBlock – a generic UIAlertViewDelegate implementation that allows you to use closures as a delegate handler. It is meant to also be a transient object like UIAlertView – which gets destroyed shortly after the alert view was dismissed. The class does this by inversing the notion of Cocoa’s delegate pattern: the alert view now retains its delegate (with the help of associated objects). Furthermore to prevent any memory leaks caused by inadvertent circular reference in the implementation blocks, it cleans up those blocks after the alert view is dismissed – making BSAlertViewDelegateBlock safer to use .

So here’s how you use it:

UIAlertView* alert = ...;
BSAlertViewDelegateBlock* alertDelegate = [[BSAlertViewDelegateBlock alloc] initWithAlertView:alert];
alertDelegate.didDismissWithButtonIndexBlock = ^(UIAlertView* alertView,NSInteger buttonIndex) {
    switch (buttonIndex) {
        ...
    }
};
[alert show];

Simple, right?

This delegate-to-block adapter saved me a ton of code writing the in-app purchase handler of Speech Timer. Initially the in-app purchase classes were carried over from a Mac app. OS X has a modal NSAlertView – thus the handler of the alert view can be placed just below the statement that shows it. Porting this over to iOS and still keeping the Mac portions operational hits a snag with the way UIAlertView operates.

Take a look at my code snippet below:

In-App Purchase Code 

As you can see for yourself, without the block-based wrapper, I would have to split the iOS half into two parts, making it even more jumbled. But massaging UIAlertView to expose a block-based API keeps the code together and coherent with their OS X counterparts.

Without further ado, here’s the code for BSAlertViewDelegateBlock for your re-use. Please let me know if you find it useful, Happy New Year!



Do you enjoy this post? Enter your e-mail address below to receive articles like this one in your mailbox.

Free Updates!

Learn how to grow your indie business while keeping your day job.

Categories

Archives

Keep updated!

Don't miss out on new articles!
%d bloggers like this: