为UIAlertView添加block支持
虽然从iOS8.0开始大家都开始用UIAlertController来做警示框了,但是市面上APP大部分还都是支持iOS7的,那么不可避免的就要面对UIAlertView处理的问题。苹果官方提供了UIAlertView的delegate代理回调的方式,但是,却经常因多重代理或者多重继承代理处理不好引起delegate无效的问题。所以,让UIAlertView支持block回调可以让程序的可读性更高,开发也更方便!下面附上代码,仅供参考。
.h文件
//
// UIAlertView+BlocksKit.h
// BlocksKit
//
#import <UIKit/UIKit.h>
/** UIAlertView without delegates!
This set of extensions and convenience classes allows
for an instance of UIAlertView without the implementation
of a delegate. Any time you instantiate a UIAlertView
using the methods here, you must add buttons using
addButtonWithTitle:handler:otherwise nothing will happen.
A typical invocation will go like this:
UIAlertView *testView = [UIAlertView alertViewWithTitle:@"Application Alert" message:@"This app will explode in 42 seconds."];
[testView setCancelButtonWithTitle:@"Oh No!" handler:^{ NSLog(@"Boom!"); }];
[testView show];
A more traditional, and more useful, modal dialog looks like so:
UIAlertView *testView = [UIAlertView alertViewWithTitle:@"Very important!" message:@"Do you like chocolate?"];
[testView addButtonWithTitle:@"Yes" handler:^{ NSLog(@"Yay!"); }];
[testView addButtonWithTitle:@"No" handler:^{ NSLog(@"We hate you."); }];
[testView show];
Includes code by the following:
- [Landon Fuller](http://landonf.bikemonkey.org), "Using Blocks".
- [Peter Steinberger](https://github.com/steipete)
- [Zach Waldowski](https://github.com/zwaldowski)
@warning UIAlertView is only available on a platform with UIKit.
*/
@interface UIAlertView (BlocksKit)
///-----------------------------------
/// @name Creating alert views
///-----------------------------------
/** Creates and shows a new alert view with only a title, message, and cancel button.
@param title The title of the alert view.
@param message The message content of the alert.
@param cancelButtonTitle The title of the cancel button. If both cancelButtonTitle and otherButtonTitles are empty or nil, defaults to a
@param otherButtonTitles Titles of additional buttons to add to the receiver.
@param block A block of code to be fired on the dismissal of the alert view.
@return The UIAlertView.
*/
+ (UIAlertView*)bk_showAlertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles handler:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))block;
/** Creates and returns a new alert view with only a title and cancel button.
@param title The title of the alert view.
@return A newly created alert view.
*/
+ (id)bk_alertViewWithTitle:(NSString *)title;
/** Creates and returns a new alert view with only a title, message, and cancel button.
@param title The title of the alert view.
@param message The message content of the alert.
@return A newly created alert view.
*/
+ (id)bk_alertViewWithTitle:(NSString *)title message:(NSString *)message;
/** Returns a configured alert view with only a title, message, and cancel button.
@param title The title of the alert view.
@param message The message content of the alert.
@return An instantiated alert view.
*/
- (id)bk_initWithTitle:(NSString *)title message:(NSString *)message NS_REPLACES_RECEIVER;
///-----------------------------------
/// @name Adding buttons
///-----------------------------------
/** Add a new button with an associated code block.
@param title The text of the button.
@param block A block of code.
*/
- (NSInteger)bk_addButtonWithTitle:(NSString *)title handler:(void (^)(void))block;
/** Set the title and trigger of the cancel button.
@param title The text of the button.
@param block A block of code.
*/
- (NSInteger)bk_setCancelButtonWithTitle:(NSString *)title handler:(void (^)(void))block;
///-----------------------------------
/// @name Altering actions
///-----------------------------------
/** Sets the block that is to be fired when a button is pressed.
@param block A code block, or nil to set no response.
@param index The index of a button already added to the action sheet.
*/
- (void)bk_setHandler:(void (^)(void))block forButtonAtIndex:(NSInteger)index;
/** The block that is to be fired when a button is pressed.
@param index The index of the button already added to the alert view.
@return A code block, or nil if no block yet assigned.
*/
- (void (^)(void))bk_handlerForButtonAtIndex:(NSInteger)index;
/** The block to be fired when the action sheet is dismissed with the cancel
button.
Contrary to setCancelButtonWithTitle:handler:, you can set this
property multiple times but multiple cancel buttons will
not be generated.
*/
@property (nonatomic, copy, setter = bk_setCancelBlock:) void (^bk_cancelBlock)(void);
/** The block to be fired before the alert view will show. */
@property (nonatomic, copy, setter = bk_setWillShowBlock:) void (^bk_willShowBlock)(UIAlertView *alertView);
/** The block to be fired when the alert view shows. */
@property (nonatomic, copy, setter = bk_setDidShowBlock:) void (^bk_didShowBlock)(UIAlertView *alertView);
/** The block to be fired before the alert view will dismiss. */
@property (nonatomic, copy, setter = bk_setWillDismissBlock:) void (^bk_willDismissBlock)(UIAlertView *alertView, NSInteger buttonIndex);
/** The block to be fired after the alert view dismisses. */
@property (nonatomic, copy, setter = bk_setDidDismissBlock:) void (^bk_didDismissBlock)(UIAlertView *alertView, NSInteger buttonIndex);
/** The block to be fired to determine whether the first non-cancel should be enabled */
@property (nonatomic, copy, setter = bk_SetShouldEnableFirstOtherButtonBlock:) BOOL (^bk_shouldEnableFirstOtherButtonBlock)(UIAlertView *alertView) NS_AVAILABLE_IOS(5_0);
@end
.m文件
//
// UIAlertView+BlocksKit.m
// BlocksKit
//
#import "UIAlertView+BlocksKit.h"
#pragma mark Delegate
@interface A2DynamicUIAlertViewDelegate : A2DynamicDelegate <UIAlertViewDelegate>
@end
@implementation A2DynamicUIAlertViewDelegate
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
BOOL should = YES;
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(alertViewShouldEnableFirstOtherButton:)])
should &= [realDelegate alertViewShouldEnableFirstOtherButton:alertView];
BOOL (^block)(UIAlertView *) = [self blockImplementationForMethod:_cmd];
if (block)
should &= block(alertView);
return should;
}
- (void)alertViewCancel:(UIAlertView *)alertView
{
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(alertViewCancel:)])
[realDelegate alertViewCancel:alertView];
id key = @(alertView.cancelButtonIndex);
void (^cancelBlock)(void) = (self.handlers)[key];
if (cancelBlock)
cancelBlock();
}
- (void)willPresentAlertView:(UIAlertView *)alertView
{
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(willPresentAlertView:)])
[realDelegate willPresentAlertView:alertView];
void (^block)(UIAlertView *) = [self blockImplementationForMethod:_cmd];
if (block)
block(alertView);
}
- (void)didPresentAlertView:(UIAlertView *)alertView
{
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(didPresentAlertView:)])
[realDelegate didPresentAlertView:alertView];
void (^block)(UIAlertView *) = [self blockImplementationForMethod:_cmd];
if (block)
block(alertView);
}
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(alertView:willDismissWithButtonIndex:)])
[realDelegate alertView:alertView willDismissWithButtonIndex:buttonIndex];
void (^block)(UIAlertView *, NSInteger) = [self blockImplementationForMethod:_cmd];
if (block)
block(alertView, buttonIndex);
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(alertView:didDismissWithButtonIndex:)])
[realDelegate alertView:alertView didDismissWithButtonIndex:buttonIndex];
void (^block)(UIAlertView *, NSInteger) = [self blockImplementationForMethod:_cmd];
if (block)
block(alertView, buttonIndex);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
id realDelegate = self.realDelegate;
if (realDelegate && [realDelegate respondsToSelector:@selector(alertView:clickedButtonAtIndex:)])
[realDelegate alertView:alertView clickedButtonAtIndex:buttonIndex];
void (^block)(UIAlertView *, NSInteger) = [self blockImplementationForMethod:_cmd];
if (block)
block(alertView, buttonIndex);
id key = @(buttonIndex);
void (^buttonBlock)(void) = (self.handlers)[key];
if (buttonBlock)
buttonBlock();
}
@end
#pragma mark - Category
@implementation UIAlertView (BlocksKit)
@dynamic bk_willShowBlock, bk_didShowBlock, bk_willDismissBlock, bk_didDismissBlock, bk_shouldEnableFirstOtherButtonBlock;
+ (void)load
{
@autoreleasepool {
[self bk_registerDynamicDelegate];
[self bk_linkDelegateMethods:@{
@"bk_willShowBlock": @"willPresentAlertView:",
@"bk_didShowBlock": @"didPresentAlertView:",
@"bk_willDismissBlock": @"alertView:willDismissWithButtonIndex:",
@"bk_didDismissBlock": @"alertView:didDismissWithButtonIndex:",
@"bk_shouldEnableFirstOtherButtonBlock": @"alertViewShouldEnableFirstOtherButton:"
}];
}
}
#pragma mark Convenience
+ (UIAlertView*)bk_showAlertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles handler:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))block
{
// If no buttons were specified, cancel button becomes "Dismiss"
if (!cancelButtonTitle.length && !otherButtonTitles.count)
cancelButtonTitle = NSLocalizedString(@"Dismiss", nil);
UIAlertView *alertView = [[[self class] alloc] initWithTitle:title message:message delegate:self.bk_dynamicDelegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil];
// Set other buttons
[otherButtonTitles enumerateObjectsUsingBlock:^(NSString *button, NSUInteger idx, BOOL *stop) {
[alertView addButtonWithTitle:button];
}];
// Set `didDismissBlock`
if (block) alertView.bk_didDismissBlock = block;
// Show alert view
[alertView show];
return alertView;
}
#pragma mark Initializers
+ (id)bk_alertViewWithTitle:(NSString *)title
{
return [self bk_alertViewWithTitle:title message:nil];
}
+ (id)bk_alertViewWithTitle:(NSString *)title message:(NSString *)message
{
return [[[self class] alloc] bk_initWithTitle:title message:message];
}
- (id)bk_initWithTitle:(NSString *)title message:(NSString *)message
{
self = [self initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
if (!self) return nil;
self.delegate = self.bk_dynamicDelegate;
return self;
}
#pragma Actions
- (NSInteger)bk_addButtonWithTitle:(NSString *)title handler:(void (^)(void))block
{
NSAssert(title.length, @"A button without a title cannot be added to the alert view.");
NSInteger index = [self addButtonWithTitle:title];
[self bk_setHandler:block forButtonAtIndex:index];
return index;
}
- (NSInteger)bk_setCancelButtonWithTitle:(NSString *)title handler:(void (^)(void))block
{
if (!title.length)
title = NSLocalizedString(@"Cancel", nil);
NSInteger cancelButtonIndex = [self addButtonWithTitle:title];
self.cancelButtonIndex = cancelButtonIndex;
[self bk_setHandler:block forButtonAtIndex:cancelButtonIndex];
return cancelButtonIndex;
}
#pragma mark Properties
- (void)bk_setHandler:(void (^)(void))block forButtonAtIndex:(NSInteger)index
{
id key = @(index);
if (block)
[self.bk_dynamicDelegate handlers][key] = [block copy];
else
[[self.bk_dynamicDelegate handlers] removeObjectForKey:key];
}
- (void (^)(void))bk_handlerForButtonAtIndex:(NSInteger)index
{
return [self.bk_dynamicDelegate handlers][@(index)];
}
- (void (^)(void))bk_cancelBlock
{
return [self bk_handlerForButtonAtIndex:self.cancelButtonIndex];
}
- (void)bk_setCancelBlock:(void (^)(void))block
{
if (block && self.cancelButtonIndex == -1) {
[self bk_setCancelButtonWithTitle:nil handler:block];
return;
}
[self bk_setHandler:block forButtonAtIndex:self.cancelButtonIndex];
}
@end

浙公网安备 33010602011771号