一般给按钮添加事件是这样的组合:
// 把点击后要调用的方法名传到@selector中
self.btn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
// 找别的地方写上方法的实现
- (void)btnClick {
}
这样写代码多不说,工程大的话还得到处找方法。
所以我写了一个分类,可以用block
来代替@selector()
,防止代码分散。
使用起来是这样的:
// button
[self.btn addTarget:self action:[self selectorBlock:^(id arg) {
NSLog(@"clicked %@", arg);
}] forControlEvents:UIControlEventTouchUpInside];
下面讲一下分类NSObject+BlockSEL.h
中的实现原理
- (SEL)selectorBlock:(void (^)(id))block {
NSString *selName = [NSString stringWithFormat:@"selector_%p:", block];
SEL sel = NSSelectorFromString(selName);
class_addMethod([self class], sel, (IMP)selectorImp, "v@:@");
objc_setAssociatedObject(self, sel, block, OBJC_ASSOCIATION_COPY_NONATOMIC);
return sel;
}
static void selectorImp(id self, SEL _cmd, id arg) {
void (^block)(id arg) = objc_getAssociatedObject(self, _cmd);
if (block) block(arg);
}
用block
的内存地址
创建一个唯一方法,并将方法实现绑定到selectorImp
函数。将block
用关联对象保存下来,在调用时执行block
。
需要注意一下,当block中使用self
时会产生循环引用,需要用__weak来修饰防止self无法释放。
__weak typeof(self) weakSelf = self;
[self.btn addTarget:self action:[self selectorBlock:^(id arg) {
weakSelf.view.backgroundColor = [UIColor whiteColor];
}] forControlEvents:UIControlEventTouchUpInside];