Quick Tip: UIAlertView with block callbacks

What bothers me

Now more than ever I find myself pondering over the question: “Why delegates? Why???”

Last time I found myself asking this was when I had to display some UIAlertViews in a project (though I really tend to stay away from them for UX reasons).

If you’ve had a little more than 10 days of experience in iOS development, you’ve probably already used these for either feedback to the user or as a way to get input from the user. Using it is pretty simple – you create an instance of the UIAlertView while assigning it a title, a message and titles for it’s button(s) and a delegate. Next, you call “show” and viola, it pops out:

Screen Shot 2013-01-31 at 11.30.17 PM

The problem starts when you want to handle the user’s action – if we’re only talking about a 1-button “OK” alert then this is a non-issue, but if there are multiple buttons here and you wish to handle the user’s action according to their choice – that’s where the spaghetti code is born.

Spaghettelegate (It is too a word!)

Now you’ll find yourself implementing yet another delegate method for when the user dismisses the alert. Won’t it go along nicely with all the other out-of-order methods and code in your class? Something like:

- (IBAction)okPressed:(id)sender {
    UIAlertView *nagAlert = [[UIAlertView alloc] initWithTitle:@"Are you sure" message:@"No, seriously are you sure??" delegate:self cancelButtonTitle:@"Not really" otherButtonTitles:@"Yes!", nil];
    [nagAlert show];
}

#pragma mark - SomeDelegate
...

#pragma mark - SomeOtherDelegate
...

#pragma mark - UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    switch (buttonIndex) {
        case 0:
            [self quitInRage];
            break;
        case 1:
            [self doSomethingNice];
            break;
        case 2:
            [self breakEverything];
            break;
        default:
            break;
    }
}

And what if you need to display more than one UIAlertView? Do you start tagging each instance when you create it and then check the tag when the delegate method is invoked? Pfff… please…

An elegant approach

The way I decided to get rid of this pattern (once and for all) is to create a block-friendly “UIBAlertView” class (B stands for Block or Brilliant or any other B-related word of your choice). So now creating, displaying and handling an alert is an all-in-one deal like so:

- (IBAction)activateAlert:(id)sender {
    UIBAlertView *alert = [[UIBAlertView alloc] initWithTitle:@"Yes, like this" message:@"What are you looking at?" cancelButtonTitle:@"Leave me alone" otherButtonTitles:@"Button 1",@"Button 2",nil];
    [alert showWithDismissHandler:^(NSInteger selectedIndex, BOOL didCancel) {
        if (didCancel) {
            NSLog(@"User cancelled");
            return;
        }
        switch (selectedIndex) {
            case 1:
                NSLog(@"1 selected");
                break;
            case 2:
                NSLog(@"2 selected");
                break;
            default:
                break;
        }
    }];
}

This is elegant because:
A. When an alert is dismissed, you know exactly which one it is.
B. You’re creating, activating and handling the dismissing of your alert in the same section of code.

The code is available on gitHub and featured in CocoaControls check it out.

Any comments, suggestions or different approaches will be hunted down and executed. Just kidding, suggest away 🙂

Advertisements

Posted on January 31, 2013, in Quick tips and tagged , , , . Bookmark the permalink. 5 Comments.

  1. what is funny is that someone created a quite similar category a few days before you : http://www.cocoacontrols.com/platforms/ios/controls/alert-blocks

  2. Thanks! Easy implementation, big gain.

  3. You should update you example to match the new handler signature :
    [alert showWithDismissHandler:^(NSInteger selectedIndex, NSString *selectedTitle, BOOL didCancel) {
    if (didCancel) {
    NSLog(@”User cancelled”);
    return;
    }
    switch (selectedIndex) {
    case 1:
    NSLog(@”1 selected”);
    break;
    case 2:
    NSLog(@”2 selected”);
    break;
    default:
    break;
    }
    }];

  1. Pingback: UIBAlertView (Cocoa Controls) | zdima.net

Say something...

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: