Objective-C Runtime之着魔的UIAlertView

前言:

上篇文章写的是Runtime的一个入门教程,刚哥问我那个Associated Objects加回调是啥时候用,那我就来告诉你啦!我们在使用UIAlertView的时候用的多。

传统的UIAlertView:

在一个类中有多个UIAlertView,不同的UIAlertView对应不同的事件,我们使用的传统方法如下:

 1 #pragma mark - action method
 2 
 3 - (IBAction)firstButtonClick:(id)sender {
 4     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
 5     alertView.tag = 1001;
 6     [alertView show];
 7 }
 8 
 9 - (IBAction)secondButtonClick:(id)sender {
10     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
11     alertView.tag = 1002;
12     [alertView show];
13 }
14 
15 - (IBAction)ThirdButtonClick:(id)sender {
16     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
17     alertView.tag = 1003;
18     [alertView show];
19 }
20 
21 #pragma mark - delegate method
22 
23 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
24 {
25     if (alertView.tag == 1001) {
26         if (buttonIndex == 1) {
27             NSLog(@"普通alertView1001执行ok");
28         }
29     } else if (alertView.tag == 1002) {
30         if (buttonIndex == 1) {
31             NSLog(@"普通alertView1002执行ok");
32         }
33     } else if (alertView.tag == 1003) {
34         if (buttonIndex == 1) {
35             NSLog(@"普通alertView1003执行ok");
36         }
37     }
38 }

我们要给每个UIAlertView赋值一个tag值,在delegate方法中还要进行tag的判断以及buttonIndex的判断,太繁琐了。

着魔的UIAlertView:

下面我们使用Category和Associated Objects进行魔法修改

创建一个UIAlertView的Category

UIAlertView+ActionBlock.h

1 #import <UIKit/UIKit.h>
2 
3 typedef void (^AlertCallBack)(UIAlertView *, NSUInteger);
4 
5 @interface UIAlertView (ActionBlock)<UIAlertViewDelegate>
6 
7 @property (nonatomic, copy) AlertCallBack callBack;
8 
9 @end

UIAlertView+ActionBlock.m

 1 #if TARGET_IPHONE_SIMULATOR
 2 #import <objc/objc-runtime.h>
 3 #else
 4 #import <objc/runtime.h>
 5 #import <objc/message.h>
 6 #endif
 7 
 8 @implementation UIAlertView (ActionBlock)
 9 
10 - (void)setCallBack:(AlertCallBack)callBack
11 {
12     objc_setAssociatedObject(self, @selector(callBack), callBack, OBJC_ASSOCIATION_COPY_NONATOMIC);
13     self.delegate = self;
14 }
15 
16 - (AlertCallBack)callBack
17 {
18     return objc_getAssociatedObject(self, @selector(callBack));
19 }
20 
21 #pragma mark - delegate method
22 
23 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
24 {
25     if (self.callBack) {
26         self.callBack(alertView, buttonIndex);
27     }
28 }

在主类中取消delegate,使用block属性

 1 #pragma mark - action method
 2 
 3 - (IBAction)firstButtonClick:(id)sender {
 4     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
 5     alertView.callBack = ^(UIAlertView *alertView, NSUInteger buttonIndex){
 6         if (buttonIndex == 1) {
 7             NSLog(@"魔法alertView1001执行ok");
 8         }
 9     };
10     [alertView show];
11 }
12 
13 - (IBAction)secondButtonClick:(id)sender {
14     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
15     alertView.callBack = ^(UIAlertView *alertView, NSUInteger buttonIndex){
16         if (buttonIndex == 1) {
17             NSLog(@"魔法alertView1002执行ok");
18         }
19     };
20     [alertView show];
21 }
22 
23 - (IBAction)ThirdButtonClick:(id)sender {
24     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
25     alertView.callBack = ^(UIAlertView *alertView, NSUInteger buttonIndex){
26         if (buttonIndex == 1) {
27             NSLog(@"魔法alertView1003执行ok");
28         }
29     };
30     [alertView show];
31 }

我们通过使用Category给UIAlertView扩展了一个block属性,当block被设置后就会调用setCallBack方法,触发self.delegate = self,即主类中的UIAlertView的delegate方法被Category中的方法覆盖。这样不仅有效解决问题,还解决了其他人修改该类的安全性(block被去掉后,原delegate恢复)

如下不给tag值为1003的UIAlertView设置block,即调用原delegate方法。

 1 - (IBAction)firstButtonClick:(id)sender {
 2     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
 3     alertView.callBack = ^(UIAlertView *alertView, NSUInteger buttonIndex){
 4         if (buttonIndex == 1) {
 5             NSLog(@"魔法alertView1001执行ok");
 6         }
 7     };
 8     alertView.tag = 1001;
 9     [alertView show];
10 }
11 
12 - (IBAction)secondButtonClick:(id)sender {
13     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
14     alertView.callBack = ^(UIAlertView *alertView, NSUInteger buttonIndex){
15         if (buttonIndex == 1) {
16             NSLog(@"魔法alertView1002执行ok");
17         }
18     };
19     alertView.tag = 1002;
20     [alertView show];
21 }
22 
23 - (IBAction)ThirdButtonClick:(id)sender {
24     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
25     alertView.tag = 1003;
26     [alertView show];
27 }
28 
29 - (IBAction)fourthButtonClick:(id)sender {
30     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"title" message:@"message" preferredStyle:UIAlertControllerStyleAlert];
31     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleCancel handler:nil];
32     UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *alertAction){
33         NSLog(@"如果你是iOS8以上的应用,这个适合你,简单明了");
34     }];
35     [alertController addAction:cancelAction];
36     [alertController addAction:okAction];
37     [self presentViewController:alertController animated:YES completion:nil];
38 }
39 
40 #pragma mark - delegate method
41 
42 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
43 {
44     if (alertView.tag == 1001) {
45         if (buttonIndex == 1) {
46             NSLog(@"普通alertView1001执行ok");
47         }
48     } else if (alertView.tag == 1002) {
49         if (buttonIndex == 1) {
50             NSLog(@"普通alertView1002执行ok");
51         }
52     } else if (alertView.tag == 1003) {
53         if (buttonIndex == 1) {
54             NSLog(@"普通alertView1003执行ok");
55         }
56     } else if (alertView.tag == 1004) {
57         if (buttonIndex == 1) {
58             NSLog(@"普通alertView1004执行ok");
59         }
60     }
61 }

uialertbyruntimenew

相关Demo下载:

https://github.com/ianisme/UIAlertViewBYRuntime_Demo

总结:

通过Associated Objects我们有效的解决了UIAlertView的繁琐问题,如果您是开发iOS8以上的应用,建议您弃用UIAlertView,苹果的UIAlertController已经有了更好的解决方案。

原文地址:https://www.cnblogs.com/fengmin/p/5403190.html