现在有一个需求, 如果一个自定义cell中有一个button, button的点击事件要将自定义cell中的某个属性值传给控制器, 应该怎么做?
当然你可以利用代理, 通知, 和block回调, 除此之外, 还有没有其他办法呢? 有! 那就是今天要说的路由响应链方法.
说到路由响应链, 其实跟路由器的路由半毛钱关系没有. 关键在于响应链, 说到响应链, 就不得不说一下UIResponder
The UIResponder class defines an interface for objects that respond to and handle events. It is the superclass of UIApplication, UIView and its subclasses (which include UIWindow). Instances of these classes are sometimes referred to as responder objects or, simply, responders.
UIResponder类定义了一个对象接口用来响应和处理事件, 它是UIApplication, UIView以及UIView的子类(包括UIWindow)的父类, 这些类的实例对象被称为响应对象或者响应者
然后UIResponder对象有一个重要的属性叫做nextResponder, 下一个响应者. 现在回到我们的需求
响应者链
当button向controller传值的时候(红色虚线箭头方向), 这是逆传, 大部分情况下我们都使用通知代理和block, 但是nextResponsder这个属性让我们可以直接获取到控件的父类
首先,我为UIResponder建立一个分类
UIResponder + Router分类
在分类中, 我实现这样一个方法
#import "UIResponder+Router.h" @implementation UIResponder (Router) - (void)routerWithEventName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { if (self.nextResponder) { [[self nextResponder] routerWithEventName:eventName userInfo:userInfo]; } } @end
第一个参数是事件名称, 第二个参数是需要传递的参数信息
看起来这样一个方法会陷入死循环, 其实不然, 当self.nextResponder向上一直找到UIApplication都还不能响应事件的时候, 系统就会自动丢弃这个事件
而当我控制器中重写这个方法的时候, 相当于重写父类方法的时候,那么系统就会走子类的方法, 那么参数就直接传递给控制器了
控制器中重写父类方法
- (void)routerWithEventName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { if ([eventName isEqualToString:YFTransferNameEvent]) { NSString * name = userInfo[YFUserName]; NSLog(@"用户的姓名为:%@",name); } }
cell中Button的点击事件
- (void)buttonClickAction:(UIButton *)sender { [sender routerWithEventName:YFTransferNameEvent userInfo:@{ YFUserName:[self userName], }]; }
也就是说, button将事件处理传递给nextResponder, 也就是cell, cell没有重写父类方法, 继续将事件传递给tableView, tableView也没有重写父类方法, 于是将事件处理传递给控制器的view,控制器的view也没有重写父类方法, 于是将事件处理传递给控制器, 控制器重写了父类方法, 于是就走控制器重写的方法, 进行事件处理, 事件就成功地从button传到了控制器.
响应者链传递
实现效果如下图, 我依次点击每一个button,(注意:不是点击cell),就会在控制器里返回出结果, 并赋值给Label
实现效果
具体的demo链接附在下面了, 有兴趣的可以看一下, 非常简单的
demo链接