Say you’re working on an iOS view controller that presents UIAlertView
s 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;
@end
UIAlertView+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