IOS UIControl使用block作为事件捕获回调

对于继承自UIControl的target-action模式,需要使用如下方式进行事件捕获

- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

其中的参数action是一个SEL(@selector),需要重新定义一个新的类成员函数,事件较多时往往需要添加更多的函数,较为麻烦。如果能使用代码块block来支持事件响应,则会方便很多。

后来在Github上看到zwaldowski/BlocksKit,该库对Objective-C提供了更多block语法支持的,其中就包括了UIControll的事件支持。

在文件UIControl+BlocksKit.m中实现了UIControl的分类,增加了add,remove,has三种事件管理,在bk_addEventHandler中,将block作为参数传入,然后对block和响应的forControlEvents通过addTarget映射到一个新的自定义的BKControlWrapper类中,即是每添加一个事件,将事件作为block作为传入创建一个新的接受事件的类实例,用该对象作为事件的接受者,实现实在是精妙!

BKControlWrapper的部分核心代码如下

@interface BKControlWrapper : NSObject <NSCopying>

// 初始化的代码
- (id)initWithHandler:(void (^)(id sender))handler forControlEvents:(UIControlEvents)controlEvents;

// 这里定义了事件类型和处理事件的block
@property (nonatomic) UIControlEvents controlEvents;
@property (nonatomic, copy) void (^handler)(id sender);

@end

@implementation BKControlWrapper

- (id)initWithHandler:(void (^)(id sender))handler forControlEvents:(UIControlEvents)controlEvents
{
    self = [super init];
    if (!self) return nil;

    self.handler = handler;
    self.controlEvents = controlEvents;

    return self;
}

// 该函数则是作为addTarget的SEL(@selector)参数,里面则是调用的block
- (void)invoke:(id)sender
{
    self.handler(sender);
}

@end

实现bk_addEventHandler的核心代码如下

- (void)bk_addEventHandler:(void (^)(id sender))handler forControlEvents:(UIControlEvents)controlEvents { NSParameterAssert(handler); // 如上,在新的对象的SEL方法中调用block BKControlWrapper *target = [[BKControlWrapper alloc] initWithHandler:handler forControlEvents:controlEvents]; [self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents]; }

举例当监听UIButton的点击事件时

[self.menuBackgroundButton bk_addEventHandler:^(id sender) {
    @strongify(self);
    [self hideMenuAnimated:YES];
} forControlEvents:UIControlEventTouchUpInside];

很方便吧。。。

BlocksKit还有很多值得继续学习的地方,这只是一个小的方面,佩服大神

你可能感兴趣的:(ios,block)