Say you’re working on an iOS view controller that presents UIAlertViews in numerous locations. Implementing button actions soon becomes a nightmare as you have to identify and handle each UIAlertView case-by-case in delegate methods such as -alertView:didDismissWithButtonIndex:.
Fortunately, we can simplify this and reduce boilerplate code with a nifty category on UIAlertView that introduces a Block-based method of presenting alerts:
[UIAlertView presentWithTitle:@"Hello"
message:@"Good day!"
buttons:@[ @"Cancel", @"Allow" ]
buttonHandler:^(NSUInteger index) {
if (index == 1) { /* allow */ }
}];With this API, we can present alerts and handle their buttons’ actions inline.
Under the hood, we assign the UIAlertView’s delegate object to itself and take advantage of the Associated Objects API to associate the button handler block with the alert view (Blocks are first-class Objective-C objects). When a button is tapped and the alert view’s delegate method fires, we invoke the cached button handler block.
UIAlertView+Additions.h
#import <UIKit/UIKit.h>
@interface UIAlertView (Additions)
+ (void)presentWithTitle:(NSString *)title
message:(NSString *)message
buttons:(NSArray *)buttons
buttonHandler:(void(^)(NSUInteger index))handler;
@endUIAlertView+Additions.m
#import "UIAlertView+Additions.h"
#import <objc/runtime.h>
@implementation UIAlertView (Additions)
static const char *HANDLER_KEY = "com.mattrajca.alertview.handler";
+ (void)presentWithTitle:(NSString *)title
message:(NSString *)message
buttons:(NSArray *)buttons
buttonHandler:(void (^)(NSUInteger))handler {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:nil];
[alert setDelegate:alert];
[buttons enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[alert addButtonWithTitle:obj];
}];
if (handler)
objc_setAssociatedObject(alert, HANDLER_KEY, handler, OBJC_ASSOCIATION_COPY_NONATOMIC);
[alert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
id handler = objc_getAssociatedObject(alertView, HANDLER_KEY);
if (handler)
((void(^)())handler)(buttonIndex);
}
@end