类ZCMAlert是一个用来展示alert框的封装类,iOS version >= 8.0 时自动使用UIAlertController,否则使用UIAlertView。
// // ZCMAlert.h // zcm // // Created by cnstar on 4/4/2015. // Copyright (c) 2015年 cnstar. All rights reserved. // #import <Foundation/Foundation.h> //系统版本号 #define SYSTEM_VERSION [[[UIDevice currentDevice] systemVersion] floatValue] @class ZCMAlertAction; /** * 封装自适应系统的ZCMAlert (UIAlertView和UIAlertController) */ @interface ZCMAlert : NSObject @property (nonatomic, readonly) NSString *title; @property (nonatomic, readonly) NSString *message; @property (nonatomic, readonly) NSArray *actions; +(instancetype)alertWithTitle:(NSString *)title message:(NSString *)message; -(void)show; -(void)addAction:(ZCMAlertAction *)action; @end /** * ZCMAlertStyle 只针对iOS 8.0及以上有效 */ typedef NS_ENUM(NSInteger, ZCMAlertStyle) { ZCMAlertStyleDefault = 0, ZCMAlertStyleCancel, ZCMAlertStyleDestructive }; typedef void(^ZCMAlertActionHandler)(ZCMAlertAction *); /** * ZCMAlertAction为alert view上的按钮动作类,一个按钮对应一个handler及一个title */ @interface ZCMAlertAction : NSObject @property (nonatomic, readonly) NSString *title; @property (nonatomic, readonly) ZCMAlertStyle style; @property (copy) ZCMAlertActionHandler handler; + (instancetype)actionWithTitle:(NSString *)title style:(ZCMAlertStyle)style handler:(void (^)(ZCMAlertAction *action))handler; @end
// // ZCMAlert.m // zcm // // Created by cnstar on 4/4/2015. // Copyright (c) 2015年 cnstar. All rights reserved. // #import "ZCMAlert.h" @interface ZCMAlert ()<UIAlertViewDelegate> @property (nonatomic, strong) NSString *title; @property (nonatomic, strong) NSString *message; @property (nonatomic, strong) NSMutableArray *mutableActions; @property (nonatomic, strong) id holder; @end //做转换 ZCMAlertStyle ——> UIAlertActionStyle static inline UIAlertActionStyle uistyle(ZCMAlertStyle style) { switch (style) { case ZCMAlertStyleCancel: return UIAlertActionStyleCancel; break; case ZCMAlertStyleDestructive: return UIAlertActionStyleDestructive; break; default: return UIAlertActionStyleDefault; break; } } @implementation ZCMAlert -(void)dealloc { [self dismiss]; self.mutableActions = nil; self.title = nil; self.message = nil; } -(void)dismiss { self.holder = nil; } +(instancetype)alertWithTitle:(NSString *)title message:(NSString *)message { return [[ZCMAlert alloc] initWithTitle:title message:message]; } -(instancetype)initWithTitle:(NSString *)title message:(NSString *)message { if ((self = [super init])) { self.title = title; self.message = message; } return self; } /** * show方法,show的时候再根据系统创建不同的alert。 * 如果在init方法就创建alert的话,务必会声明一个id alert变量供addAction使用 * 此时如果用户没有再调用show方法,此时UIAlertController会hold住self,导致不能跑到dealloc而内存泄漏 */ -(void)show { if (SYSTEM_VERSION >= 8.0) { UIAlertController *alert = [UIAlertController alertControllerWithTitle:_title message:_message preferredStyle:UIAlertControllerStyleAlert]; for (ZCMAlertAction *action in _mutableActions) { [alert addAction:[UIAlertAction actionWithTitle:action.title style:uistyle(action.style) handler:^(UIAlertAction *alertAction) { [self processForClicked:action]; [self dismiss]; }]]; } UIViewController *viewController = [UIApplication sharedApplication].keyWindow.rootViewController; if (!viewController) { for (UIWindow *window in [UIApplication sharedApplication].windows) { if (window.rootViewController) { viewController = window.rootViewController; } } } [viewController presentViewController:alert animated:YES completion:nil]; } else { self.holder = self; //在show之前先hold住self,以便能够正常回调action。原因是,如果不hold住当前self的话,show方法结束后self即被释放,此时UIAlertView的delegate=nil,导致不能正常回调 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:_title message:_message delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil]; for (ZCMAlertAction *action in _mutableActions) { [alert addButtonWithTitle:action.title]; } [alert show]; } } -(void)processForClicked:(ZCMAlertAction *)action { ZCMAlertActionHandler block = action.handler; //此处不直接使用action.handler的原因是,如果多线程操作,刚进入if(action.handler){//此时正好被其他线程修改了action.handler=nil,那么下面调研action.handler()将会crash,因为block已经不存在了}。 ps:此处不会有多线程调用,只是为了时刻保持良好的认知 if (block) { block(action); } } -(NSArray *)actions { return _mutableActions; } -(void)addAction:(ZCMAlertAction *)action { if (!_mutableActions) { self.mutableActions = [NSMutableArray array]; } if (action) { [_mutableActions addObject:action]; } } #pragma mark - UIAlertView Delegate for iOS < 8.0 -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex >= 0 && buttonIndex < _mutableActions.count) { ZCMAlertAction *action = [_mutableActions objectAtIndex:buttonIndex]; [self processForClicked:action]; } [self dismiss]; //必须调用,把holder置为nil, 否则最后self释放不了,会内存泄漏 } - (void)alertViewCancel:(UIAlertView *)alertView { [self dismiss]; //必须调用,把holder置为nil, 否则最后self释放不了,会内存泄漏 } - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { [self dismiss]; //必须调用,把holder置为nil, 否则最后self释放不了,会内存泄漏 } @end #pragma mark - ZCMAlertAction @interface ZCMAlertAction () @property (nonatomic, strong) NSString *title; @property (nonatomic, assign) ZCMAlertStyle style; @end @implementation ZCMAlertAction -(void)dealloc { self.title = nil; self.handler = nil; } + (instancetype)actionWithTitle:(NSString *)title style:(ZCMAlertStyle)style handler:(void (^)(ZCMAlertAction *action))handler { return [[ZCMAlertAction alloc] initWithTitle:title style:style handler:handler]; } - (instancetype)initWithTitle:(NSString *)title style:(ZCMAlertStyle)style handler:(void (^)(ZCMAlertAction *action))handler { if ((self = [super init])) { self.title = title; self.handler = handler; self.style = style; } return self; } @end
使用方法如下:
ZCMAlert *alert = [ZCMAlert alertWithTitle:@"提示" message:@"我是提示消息!"]; [alert addAction:[ZCMAlertAction actionWithTitle:@"知道了" style:ZCMAlertStyleDefault handler:^(ZCMAlertAction *action) { //NSLog(@"----------------------%@", action.title); }]]; [alert show];
ps:第一次开始写博客,故只会贴代码,记流水帐。难免有错误之处,望大家不吝赐教。谢谢!