第一响应者

作者: 未之 | 来源:发表于2017-03-31 18:11 被阅读715次

第一响应者 (The First Responder)
  什么是第一响应者?简单的讲,第一响应者是一个UIWindow对象接收到一个事件后,第一个来响应的该事件的对象。注意:这个第一响应者与触摸检测到的第一个响应的UIView并不是一个概念。第一响应者一般情况下用于处理非触摸事件(手机摇晃、耳机线控的远程空间)或非本窗口的触摸事件(键盘触摸事件),通俗点讲其实就是管别人闲事的响应者。在IOS中,当然管闲事并不是所有控件都愿意的,这么说好像并不是很好理解,或着是站在编程人员的角度来看待这个问题,程序员负责告诉系统哪个对象可以成为第一响应者(canBecomeFirstResponder),如果方法canBecomeFirstResponder返回YES,这个响应者对象才有资格称为第一响应者。有资格并不代表一定可以成为第一响应者,还要becomeFirstResponder正式成为第一响应者。同时也有对应的canResignFirstResponder和resignFirstResponder是否可以解除第一响应者。

值得注意的是,一个UIWindow对象在某一时刻只能有一个响应者对象可以成为第一响应者。我们可以通过isFirstResponder来判断某一个对象是否为第一响应者。

我们可以用苹果的私有方法来获得第一响应者

    UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
    UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];

下面我们用摇一摇事件来说一说第一响应者响应事件流程

代码

在视图控制器中
- (void)viewDidLoad {
    [super viewDidLoad];
    
    HeaderView *headerView = [[HeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 200)];

    headerView.backgroundColor = [UIColor redColor];
    
    [self.view addSubview:headerView];
    
}

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {

    NSLog(@"~~~~~~~~~motionBegan");
    
    
    UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
    UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];
    
    
}

在晃动手机后,我们可以看到断点打印的firstResponder为空。

断点

此时的调用流程为:

调用流程

这个时候却响应了摇一摇事件,为什么呢?系统这个时候会找到当前视图,即self.view,如果self.view如果不能响应,则会依据响应链找到能够响应该事件的响应者,在这里self.view.nextResponse就是ViewController,所以会响应这个摇一摇事件。

然后我们在HerderView里面加入一些代码

@interface HeaderView ()

@end

@implementation HeaderView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
//        [self becomeFirstResponder];

    }
    return self;
}

//- (BOOL)canBecomeFirstResponder {
//
//    return YES;
//}

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {

    UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
    UIView *firstResponder = [keyWindow performSelector:@selector(firstResponder)];
    
}

然后摇一摇事件,发现HeaderView并没有响应摇一摇事件,而是还是由ViewController来响应的。

然后我们将注释的部分打开,注意这里让HeaderView成为响应者,注意一定要写canBecomeFirstResponder函数,不然HeaderView就算写了becomeFirstResponder也不能成为第一响应者,然后摇一摇可以看到HeaderView的motionBegan调用了,HeaderView响应了这个事件,同时这个时候的第一响应者为HeaderView,函数调用流程为:

调用流程

然后将HeaderView的motionBegan函数注释掉,摇一摇,然后发现ViewController的motionBegan函数调用了,这个时候事件由第一响应者HeaderView传递给了ViewController,事件的调用流程:

调用流程

在这里我们看到调用流程里有forwardMethodIntld函数,推测他就是在响应链中的响应者无法响应事件时进行转发到下一个响应者的函数,

在这里我们可以分析一下

  1. 在HeaderView没有成为第一响应者,摇一摇的时候有一个forwardMethodIntld函数,这个时候由self.view进行开始响应,但是self.view并不能响应该事件,然后向上传递给ViewController,而ViewController能够响应事件,然后事件到这里被处理,不会继续传递下去,所以进行了一次转发。
  2. 在HeaderView成为第一响应者,然后也有摇一摇事件motionBegan响应的时候,事件直接找到第一响应者,发现第一响应者能够响应该事件,事件到此结束,所以这里没有forwardMethodIntld函数,也就没有进行事件的转发。
  3. 在HeaderView成为第一响应者,然后没有响应摇一摇事件motionBegan的时候,ViewController响应了该事件,发现这里有两个forwardMethodIntld函数,原因是找到第一响应者HeaderView的时候,发现并不能响应该事件,然后由响应链的上一层self.view响应,self.view也不能响应该事件,然后找到self.view的上一层,即ViewController,然后响应该事件,所以这里进行了两次事件的转发。

相关文章

  • iOS 使用响应者和响应者链处理事件

    内容概览 综述 确定一个事件的第一响应者(First Responder) 确定哪个响应者包含一个触控事件 改变响...

  • 事件的分发和传递

    响应者: 在iOS中,响应者为能响应事件的UIResponder子类对象,如UIButton、UIView等。 响...

  • iOS触摸事件探究

    目录一、基本概念1.1、UITouch1.2、UIEvent1.3、UIResponder二、查找第一响应者三、响...

  • 第一响应者

    第一响应者 (The First Responder)什么是第一响应者?简单的讲,第一响应者是一个UIWindow...

  • 关于第一响应者身份

    获得第一响应者身份 [self.searchBarbecomeFirstResponder]; 失去第一响应者身份...

  • iOS中触摸事件的响应者链及手势识别器

    用户触摸事件是依赖于响应者链来处理 -响应者链:第一响应者是视图或者其子类主要负责接收用户触摸事件;第一响应者会将...

  • 事件处理流程--响应者链

    事件分发:自上而下响应者链:自下而上 第一响应者(First responder)指的是当前接受触摸的响应者对象,...

  • iOS开发:浅谈响应链与事件传递

    响应链: 第一响应者到application对象的一系列响应者形成的链条 如何寻找第一响应者: 1、当iOS程序发...

  • 响应链(二)

    应者链如何决定第一响应者???? Determining an Event's First Responder U...

  • 响应者链

    1.1 响应者链 当与某控件交互时,该控件将作为"第一响应者 (First Responder)",作为响应者链的...

网友评论

    本文标题:第一响应者

    本文链接:https://www.haomeiwen.com/subject/fvmvottx.html