BlocksKit初见:一个支持将delegate转换成block的Cocoa库

简单介绍

BlocksKit 是一个开源的框架,对 Cocoa 进行了扩展。将很多须要通过 delegate 调用的方法转换成了 block。在非常多情况下。blocks 比 delegate 要方便简单。由于 block 是紧凑的,能够使代码简洁。提高代码可读性。另外 block 还能够进行异步处理。使用 block 要注意避免循环引用。

文件夹结构

BlocksKit 的全部方法都以bk_开头,这样能够方便地列出全部 BlocksKit 的全部方法。BlocksKit 主要文件夹结构

  • Core:存放 Foundation 相关的 Block category,如 NSObject、NSTimer、NSarray、NSDictionary、NSSet、NSIndexSet、NSMutableArray等
  • DynamicDelegate:动态代理(消息转发机制)
  • UIKit:扩展了 UIAlertView。UIActionView,UIButton 等

最经常使用的是 UIKit Category。它为 UIAlertView,UIActionSheet,UIButton,UITapGestureRecognizer 等提供了 blocks。

使用方法实例

UIAlertView 和 UIActionSheet 使用方法演示样例:

UIAlertView *alertView = [[UIAlertView alloc] bk_initWithTitle:@"提示" message:@"提示信息"];
[alertView bk_setCancelButtonWithTitle:@"取消" handler:nil];
[alertView bk_addButtonWithTitle:@"确定" handler:nil];
[alertView bk_setDidDismissBlock:^(UIAlertView *alert, NSInteger index) {
    if (index == 1) {
        NSLog(@"%ld clicked",index);
    }
}];
[alertView show];
[[UIActionSheet bk_actionSheetCustomWithTitle:nil buttonTitles:@[@"查看", @"退出"] destructiveTitle:nil cancelTitle:@"取消" andDidDismissBlock:^(UIActionSheet *sheet, NSInteger index) {

}] showInView:self.view];

UIButton 和 UITapGestureRecognizer 使用方法演示样例:

UIButton *button = [[UIButton alloc] init];
[button bk_addEventHandler:^(id sender) {

} forControlEvents:UIControlEventTouchUpInside];
UITapGestureRecognizer *tapGestureRecognizer = [UITapGestureRecognizer bk_recognizerWithHandler:^(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) {
    if (state == UIGestureRecognizerStateRecognized) {
        ...
    }
}];

UIButton 和 UIGesture 将 target-action 转换成 block,实现较简单:

- (id)bk_initWithHandler:(void (^)(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location))block delay:(NSTimeInterval)delay
{
    self = [self initWithTarget:self action:@selector(bk_handleAction:)];
    if (!self) return nil;

    self.bk_handler = block;
    self.bk_handlerDelay = delay;

    return self;
}

- (void)bk_handleAction:(UIGestureRecognizer *)recognizer
{
    void (^handler)(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) = recognizer.bk_handler;
    if (!handler) return;

    ...

    if (!delay) {
        block();
        return;
    }

    ...
}

delegate 转换成 block 实际上使用了消息转发机制,是 BlocksKit 源代码中最难理解的部分。

原理分析: 消息转发机制

当一个对象收到它没实现的消息的时候。一般会发生例如以下的情况。

  1. 调用+(BOOL)resolveInstanceMethod:(SEL)aSEL,假设对象在这里动态加入了selector 的实现方法,则消息转发结束,否则运行步骤2
  2. 调用 - (id)forwardingTargetForSelector:(SEL)aSelector,在这里你能够将消息转发给其它对象。假设实现则消息转发结束,否则运行步骤3
  3. 运行完整的消息转发机制,调用-(void)forwardInvocation:(NSInvocation *)invocation 在这一步,你能够改动消息的不论什么内容。包含目标(target),selector,參数。

    假设没有实如今这里还未实现转发则程序将抛出异常。

原理实例分析

BlocksKit 动态代理实现方式是最后一步,即-(void)forwardInvocation:(NSInvocation *)invocation,使得动态代理能够接受随意消息。

以UIAlertView为例。UIAlertView在运行时动态关联了A2DynamicUIAlertViewDelegate

@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:"
        }];
    }
}

A2DynamicUIAlertViewDelegate 是 A2DynamicDelegate 的子类。并实现了UIAlertViewDelegate 的方法

代理消息的转发由 A2DynamicDelegate 完毕

- (void)forwardInvocation:(NSInvocation *)outerInv
{
    SEL selector = outerInv.selector;
    A2BlockInvocation *innerInv = nil;
    if ((innerInv = [self.invocationsBySelectors bk_objectForSelector:selector])) {
        [innerInv invokeWithInvocation:outerInv];
    } else if ([self.realDelegate respondsToSelector:selector]) {
        [outerInv invokeWithTarget:self.realDelegate];
    }
}


注: 文章由我们 iOS122(http://www.ios122.com)的小伙伴 @鱼 整理,喜欢就一起參与: iOS122 任务池

时间: 2024-10-09 16:50:51

BlocksKit初见:一个支持将delegate转换成block的Cocoa库的相关文章

用c语言写一个函数把十进制转换成十六进制(转)

#include "stdio.h" int main() { int num=0;int a[100]; int i=0; int m=0;int yushu; char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};printf("请输入一个十进制整数:"); scanf("%d",&num); while(num>0) { y

写一个函数将传入的字符串转换成驼峰表示法

/* *已知有字符foo="get-element-by-id".写一个function将其转换成驼峰表示法"getElementById" */ var o = { trans:function (msg){ var i, tempArr = msg.split('-'), len = tempArr.length; for(i = 1; i < len; i++){ tempArr[i] = tempArr[i].charAt(0).toUpperCase

Java 里把 InputStream 转换成 String 的几种方法

我们在 Java 中经常会碰到如何把 InputStream 转换成 String 的情形,比如从文件或网络得到一个 InputStream,需要转换成字符串输出或赋给别的变量. 未真正关注这个问题之前我常用的办法就是按字节一次次读到缓冲区,或是建立 BufferedReader 逐行读取.其实大可不必费此周折,我们可以用 Apache commons IOUtils,或者是 JDK 1.5 后的 Scanner,还可用 Google  Guava 库的 CharStreams.到了 JDK7,

怎么将ppt转换成pdf软件

怎么将ppt转换成pdf软件是否使用过PPT的用户看到别人有做得非常好的PPT自己也想拷贝一份留下来?那么,笔者向你推荐迅捷PPT转换成PDF转换器来转换你的PPT格式文档,使它变得容量更小的PDF文件供你在在上传至网上或保存在电脑里面,让你远方份亲朋好友都能欣赏到你的作品. 下载安装好PPT转换PDF软件之后,进入页面,勾选“PPT转PDF”转换模式,然后可将制作好的PPT演示文稿上传到软件界面上,点击一键转换,即可实现完美的转换效果. 从PPT转PDF文件的实际效果和质量来看,当前最新发布升

PPT转换成PDF文件的方法

PPT转换成PDF文件的方法遇到个头疼的问题,要把PPT转换成PDF格式的文件,不知道该怎么办!在网上搜索了好久看到各种不同的软件,平时没有遇到过也没有使用过,现在好多软件一下都出来了,也不知道到底哪个软件才是比较好的.我平时比较讨厌下载软件,感觉麻烦下载安装什么的,所以希望找到一款有效的软件,这样就能省去试用的过程,当然也就只需要一次下载一次安装就能达到目的,多好.所以,我就在网上求助大家,让大家给我推荐一个比较好用的软件. 果然网络是万能的,热心的网友特别多,给出了宝贵的意见,大家普遍说好的

pdf在线转换成word免费版的转换器

pdf在线转换成word免费版的转换器应该说,PDF文档的规范性使得浏览者在阅读上方便了许多,但是倘若要从里面提取些资料,实在是麻烦,有没有一个快捷pdf在线转换成word免费版的转换器迅速实现软件转换呢?事实上无需下载专业电脑端软件在线瞬间实现转换. 网上在线的PDF转换软件很多,但是能够达到完美转换效果的转换器少之又少,尤其是带图片,文字混排的,并不容易转换.这里本人也是经过千辛万苦才获得的一款不错的PDF转换软件,跟网友分享一下: 1.word,excel,ppt作为微软office套件中

Java 把 InputStream 转换成 String 的几种方法

我们在 Java 中经常会碰到如何把 InputStream 转换成 String 的情形,比如从文件或网络得到一个 InputStream,需要转换成字符串输出或赋给别的变量. 未真正关注这个问题之前我常用的办法就是按字节一次次读到缓冲区,或是建立 BufferedReader 逐行读取.其实大可不必费此周折,我们可以用 Apache commons IOUtils,或者是 JDK 1.5 后的 Scanner,还可用 Google  Guava 库的 CharStreams.到了 JDK7,

PHP算法--将数字金额转换成大写金额

最近在看一些PHP算法题,遇到一个将数字金额转换成大写金额的小算法题,这里贴出自己的一个例子. 注:这个小算法适用于10万以内的金额. <?php //$num = 12345.67; function RMB_Upper($num) { $num = round($num,2); //取两位小数 $num = ''.$num; //转换成数字 $arr = explode('.',$num); $str_left = $arr[0]; // 12345 $str_right = $arr[1]

C语言将字符串转换成对应的数字(十进制、十六进制)【转】

转自:http://wawlian.iteye.com/blog/1315133 问题1:讲一个十进制数字的字符串表示转换成对应的整数.举例:将“1234”转换成整数1234. C代码 收藏代码 /*将字符串s转换成相应的整数*/ int atoi(char s[]) { int i; int n = 0; for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i) { n = 10 * n + (s[i] - '0'); } return n;