一、简单介绍事件
在iOS上,事件有很多形式:
- 触摸事件
- 运动事件
远程控制事件
我们开发中接触最多的就是触摸事件,这里我简单介绍下触摸事件,详细后期我会在博客中介绍:当用户触摸屏幕时,事件会被封装成一个event实例,包含了触摸事件的相关信息,event实例中包含着若干个UITouch实例,一个touch表示一根手指。触摸事件在屏幕上有一个周期,即触摸开始、触摸点移动、触摸结束还有中途取消。
二、事件的传递
从事件的发生到其处理的对象,传递需要一段特殊的过程。当用户点击设备屏幕时,iOS捕捉到一系列的触摸,将其打包到UIEvent对象中并放置到应用程序活动事件队列中。UIApplication对象从事件队列中取出最前面的事件将其分发。通常,其发送事件给应用程序的主窗口–UIWindow实例,再由窗口对象发生事件给“第一响应者(触摸的视图)”处理。
由上图细心的同学可以发现,window分发事件时会先分发给Gesture recognizer(手势,后期我会用博客详细介绍),再分发给View(视图),我专门敲了个demo(添加一个button,再上面添加任意一个手势),看了一下,确实先执行手势的触发事件,再触发按钮自身的触摸事件。
三、响应者链
1. 事件响应者的基本概念
响应者对象是一个能接收并处理事件的对象。UIResponser是所有响应者对象的基类。该基类定义了一系列的编程接口,不但为事件处理进行服务而且还提供了通用的响应者行为处理。UIApplication、UIView(包括UIWindow),UIViewController都直接或间接的继承自UIResponser,所有的这些类的实例都是响应者对象。
2. 响应者链的概念
响应者链表示一系列的响应者对象。事件被交由第一响应者对象处理,如果第一响应者不处理,事件被沿着响应者链向上传递,交给下一个响应者(next responser)。
3. 事件响应者链传递的过程
- 当用户与视图交互时,将会消息传递给视图控制器,如果不存在控制器,传递给父视图。
- 如果不处理该消息,则继续将消息向上传递
- 最上层的视图如果也不处理,将事件交予Window对象
最后交由UIApplication实例,如果不处理,则丢弃事件
4. 事件响应者链传递的原理的实践
如果最上层的子视图不会响应用户事件即userInteractionEnabled为NO,那么事件相当于没有第一响应者,也就无法向上传递。 而我在项目中遇到一个问题:就是单元格UITableViewCell点击几乎没法进入选中单元格那个代理方法中,只是偶尔会进入,而监控TableView实时滑动的代理方法却正常进入,非常奇怪。后来才发现原来我那个单元格填充的区域几乎全部是UILabel控件,而UILabel控件的userInteractionEnabled默认NO,不接收用户事件,那么事件无法传递给UITableView了,所以没法跳入单元格选中的代理方法中。