您的位置:首页 > 移动开发 > IOS开发

[iOS] #运行时编程# Block植入

2015-08-25 14:48 417 查看
运行时编程之 Block植入

CallBack-回调,在各个编程语言中都是很重要的一个功能,比如弹窗一个子控件,在子控件中获取到信息后需要返回数据给调用方,最主流的做法就是把调用方作为参数传到子控件中,然后当子控件拿到信息以后再把信息传递给之前进来的调用方。在iOS中,是通过一种叫delegate(代理)的方式来实现,通常在创建子控件的时候会看到一句:子控件.delegate = self, 意思是说,我就是这个子控件的代理,当子控件需要回调的时候,就直接调用其成员delegate(也就是我),
就可以把信息传递回去。

然而在很多情况下这样的代理会显得很‘啰嗦’,比如我只是想简单的弹出一个对话框(UIAlertView)然后知道用户选择的是Ok还是Cancel, 却要在调用方做两件事,首先是声明这个对话框的协议(protocol)用以具备接收对话框回调的资格,然后再去实现回调方法,比如OnOk, OnCancel,等等,更麻烦的是,如果我在此有三个对话框的话,就要实现多个协议,做他们的代理。

所以这里可以用Block对其闭包,直接在上下文的地方声明回调,不仅不用增加回调方法,而且很轻易的解决了多重回调的复杂局面。现在就拿UIAlertView举一个例子:

正常做法:调用方在召唤alertview的同时,将其代理指向自己:alertview.delegate = self; 然后在用户点击对话框上面的按钮的时候,触发其回调方法(如果它的代理存在的前提,如果没有声明指向的话不会被调用):

// Called when a button is clicked. The view will be automatically dismissed after this call
returns
- (void)alertView:(UIAlertView*)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex;
这里的优化思路是:
修改UIAlertView这个类,增加一个block对象,然后让其自己做自己的delegate, 调用方将block作为参数传进去以后,在自己的clickedButtonAtIndex方法中调用block即可。
具体实现:
1. 创建UIAlertView的类扩展,UIAlertView+Block;
2. 声明回调Block:
typedefvoid (^UIAlertViewCompletionBlock)
(UIAlertView *alertView,NSInteger buttonIndex);
3. 增加接口,将block传进来.

+ (instancetype)showWithTitle:(NSString
*)title
message:(NSString *)message
style:(UIAlertViewStyle)style

cancelButtonTitle:(NSString *)cancelButtonTitle

otherButtonTitles:(NSArray *)otherButtonTitles

tapBlock:(UIAlertViewCompletionBlock)tapBlock;
4. 在设置tapBlock的时候,修改对象,新增成员变量,此处是核心:

objc_setAssociatedObject(self,UIAlertViewTapBlockKey,
tapBlock,OBJC_ASSOCIATION_COPY);
*UIAlertViewTapBlockKey
不是字符串,是一个void*, 与tapBlock形成K-V唯一配对,向一个UIAlertView查key,就可以得到tapBlock作为value返回。 这里的setAssociatedObject是运行时编程中API,所以需要#import<objc/runtime.h>
此时,tapBlock就已被植入到对象UIAlertView中,同时可以用key-value的方式获取。
5.将代理指向自己

self.delegate
= (id<UIAlertViewDelegate>)self;
6.实现代理方法- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex,在里面调用植入的tabBlock.
打完收工~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: