0%

iOS事件处理和响应链概述

App启动后发生了什么

应用启动及事件分发

App在启动之后, 会立即与负责传底层递用户事件的系统组件建立连接. 由于App必须依次单独的处理这些底层事件, 所以底层事件在发生之后会首先被加入到一个event queue中, 然后按照first-in first-out的顺序派发到App中.

一旦用户界面初始化完成, App就开始由外部用户事件驱动. Application object会从event queue中取出队首对象, 并将其转换成一个UIEvent对象, 然后将其分发给应用内的其他对象进行处理. 这个过程会一直持续到应用程序终止.

事件响应及应用状态更新

App加载完成后, 还会设置一组负责绘制用户界面和处理事件的核心对象, 包括UIWindow和各种类型的UIView. 当Application object从event queue中获取到一个用户事件后, 会先将事件发送到用户事件发生的UIWindow, 然后UIWindow会将事件下发给合适的View进行处理.

在处理事件的过程中, view会通过一系列动作来更新应用的状态和数据, 当这些动作完成之后, 控制权会重新交还给Application object, 以便继续从event queue中获取下一个事件.

事件的传递和响应

注: 这里所说的事件, 只是用户通过手指与屏幕交互的事件(Touch events), 不包括其他类型的事件.

上面说过, 当Application object从event queue中获取到一个用户事件后, 会首先将事件发送到用户事件发生的UIWindow, 然后UIWindow会将事件下发给合适的View进行处理.

严格来说, 这个过程可以分解为两步, 首先是寻找交互事件发生的View, 然后才是选择处理事件的first responder. 这里要注意的事, 事件发生的View, 并不一定会处理该事件, 也就不是该事件的first responder.

寻找用户交互的”案发现场”

UIKit使用基于view的hit-testing机制来确定交互事件的发生地. hit-testing机制主要包括两个方法:hitTest:withEvent:pointInside:withEvent:.

hit-testing机制的主要调用流程如下:

  1. 首先调用当前view的*pointInside:withEvent:*方法, 判断触摸点是否在当前视图范围内.
  2. pointInside:withEvent:返回NO, 则hitTest:withEvent: 返回nil, 说明触摸点不在当前视图可视范围内,对当前视图及视图层级的遍历终止;
  3. 若*pointInside:withEvent:返回YES, 则继续按照视图层级从上到下遍历当前视图的所有子视图, 调用其hitTest:withEvent:*方法, 直到某个子视图返回非nil的视图对象, 流程结束.
  4. 若所有子视图都返回nil, 则当前view的*pointInside:withEvent:*方法返回self.
    

概括来说, 事件发生地的寻找是通过由大到小,层层递进遍历的策略来实现的.

寻找First responder

在iOS中, 下面图中的对象都可以是事件的响应者:

在定位到事件发生的view之后, 如果该view能够处理改该事件, 则事件交付其进行处理. 如果该view不能处理该事件, 则会调用其nextResponder方法, 将事件传递下responder chain的下一个节点上, 直到找到事件的First responder, 如果该事件在整个responder chain都无法处理, 则会被丢弃.

iOS(left)和OSX(right)中的responder chain

常用名词解释

  • UITouch: An object representing the location, size, movement, and force of a touch occurring on the screen.
  • UIEvent: An object that describes a single user interaction with your app, including touch events, motion events, remote-control events, and press events.
  • UIResponder: An abstract interface for responding to and handling events.
  • Application object: An application object is responsible for the initial routing of user events and overall management of a running application. When an application is launched, it creates the application object in its main function.
  • Main event loop: In the main event loop, an application continuously routes incoming events to objects for handling and, as a result of that handling, updates its appearance and state.
  • First responder: the most appropriate responder object to handle the event.