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 任务池

转载于:https://www.cnblogs.com/liguangsunls/p/7357223.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据操作、用户权限管理等关键技术。 数据设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据设计文件。这些文件通常包括数据结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值