响应链之nextResponder

在cocochina上看到一篇文章《巧用UIResponder进行事件传递》,发现了UIResonder类的nextResponder属性。由于原文涉及的内容比较多,所以我自己专门将该知识点进行了一下整理。这是一个很有用的属性,对于UIView,nextResponder就是其SuperView或者ViewController,这样在做事件传递的时候可以不用设置delegate或block。

看一个例子前,我先提一下2个知识点:
  • 事件响应链:当用户点击一个UIView时,系统会产生一个事件,并将其放入UIApplication的事件队列中。然后该事件会顺着这条链传递到用户点击的那个UIView:UIApplication->UIWindow->RootView->...->Subview。然后开始处理这个事件,若Subview不处理,事件将会传递给其�视图控制器,若没有控制器则传给其superView,最后传给UIWindow,UIApplication。若UIApplication还是没处理则将事件传给nil。
响应链之nextResponder_第1张图片
图片来源:伯乐在线-alanwangmodify.png
  • UIResponder具有nextResponder属性,也就是其SuperView或是UIViewConterller等。UIView是UIResponder的子类,所以UIView及其子类都能使用此属性。

好了,现在可以看这个应用实例:点击cell上的按钮,将事件传给ViewController,显示点击的cell的index。之前没用nextResponder属性,把事件从cell上的按钮传到ViewController需要将VIewController作为参数传入cell或者设置代理与block。

响应链之nextResponder_第2张图片
Paste_Image.png

响应链之nextResponder_第3张图片
Paste_Image.png

1.首先为UIResponder创建一个分类,

 #import
@interface UIResponder (Router)
-(void)routerEvent:(id)info;
@end 

 #import "UIResponder+Router.h"
@implementation UIResponder (Router)
-(void)routerEvent:(id)info{
    [self.nextResponder routerEvent:info];
}
@end ```

2.然后在ViewController中加入一个UITableview和UILable;
```Object-C
#import "ViewController.h"
#import "TableViewCell.h"
#import "UIResponder+Router.h"
@interface ViewController ()
@property(strong, nonatomic)UILabel *mLbl;
@property(strong, nonatomic)UITableView *mTableView;
@end
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    CGFloat w0 = self.view.bounds.size.width;
    CGFloat h0 = 80.;
    _mLbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, w0, h0)];
    _mLbl.backgroundColor = [UIColor orangeColor];
    _mLbl.textColor = [UIColor whiteColor];
    _mLbl.font = [UIFont systemFontOfSize:35.];
    _mLbl.textAlignment = NSTextAlignmentCenter;
    CGFloat w1 = w0;
    CGFloat h1 = self.view.bounds.size.height - h0;
    CGFloat y1 = h0;
    _mTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, y1, w1, h1)];
    _mTableView.dataSource = self;
    [_mTableView registerClass:[TableViewCell class] forCellReuseIdentifier:@"CELL"];
    
    [self.view addSubview:_mLbl];
    [self.view addSubview:_mTableView];
}

#pragma mark UITableViewDataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 20;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL" forIndexPath:indexPath];
    [cell reloadData:indexPath.row];
    
    return cell;
}
//接收事件
-(void)routerEvent:(id)info{
    _mLbl.text = info;
}

@end

TableViewCell;

#import 

@interface TableViewCell : UITableViewCell

-(void)reloadData:(NSInteger)index;

@end 

#import "TableViewCell.h"
#import "UIResponder+Router.h"

@interface TableViewCell ()

@property(assign, nonatomic)NSInteger mIndex;
@property(strong, nonatomic)UIButton *mBtn;

@end

@implementation TableViewCell

-(void)reloadData:(NSInteger)index{
    _mIndex = index;
    [_mBtn setTitle:[NSString stringWithFormat:@"%li",_mIndex] forState:UIControlStateNormal];
}

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        _mBtn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width*0.5, self.frame.size.height*0.8)];
        _mBtn.backgroundColor = [UIColor purpleColor];
        [_mBtn addTarget:self action:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:_mBtn];
    }
    return self;
}

//传递事件
-(void)btnAction{

    [self routerEvent:[NSString stringWithFormat:@"%li",_mIndex]];
}

@end```

总得来说,拿到nextResponder就拿到了view的下一个事件响应者,至于怎么操作,可以自己拓展。

你可能感兴趣的:(响应链之nextResponder)