关于IOS中的响应者链
今天简单的谈一下IOS开发中经常用到的响应者链,
在ios开发中所有能够响应touch事件的对象都继承自UISResponder
在平时的应用中当我们触碰手机界面的时候系统会将一个操作封装成一个UIEvent事件放到队列里,然后Applicagtion从事件队列中取出这个事件来寻找响应者, 然后再进行相对应的事件处理。
在寻找响应者的过程中 IOS每经过一个层级就会去寻找这个对象的
-(UIView*)hitTest(CGPoint)point event方法 返回当前视图层中响应触控电最深的视图
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event返回视图是否包含指定的某个点。
那么很显然的 学过数据结构的同学都知道 这样的响应结构就是一个树形的响应链,一层一层的找下去。
如果没有找到这个响应者 那么事件会被抛弃。 如果找到了这个响应者那么事件会开始进行处理, 找到相对应的响应者。
一般响应者的事件有如下几个 :
-----------------------------------------------------------------------------------------------------------------------
// Generally, all responders which do custom touch handling should override all four of these methods.
// Your responder will receive either touchesEnded:withEvent: or touchesCancelled:withEvent: for each
// touch it is handling (those touches it received in touchesBegan:withEvent:).
// *** You must handle cancelled touches to ensure correct behavior in your application. Failure to
// do so is very likely to lead to incorrect behavior or crashes.
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
-----------------------------------------------------------------------------------------------------------------------
如果当前的响应者没有响应这个事件, 那么响应者会调用Responder。nextResponder来传递当前的事件并且处理。
附录:IOS的响应者事件在Runloop中的实现大概如下
苹果注册了一个 Source1 (基于 mach port 的) 用来接收系统事件,其回调函数为 __IOHIDEventSystemClientQueueCallback()。
当一个硬件事件(触摸/锁屏/摇晃等)发生后,首先由 IOKit.framework 生成一个 IOHIDEvent 事件并由 SpringBoard 接收。这个过程的详细情况可以参考这里。SpringBoard 只接收按键(锁屏/静音等),触摸,加速,接近传感器等几种 Event,随后用 mach port 转发给需要的App进程。随后苹果注册的那个 Source1 就会触发回调,并调用 _UIApplicationHandleEventQueue() 进行应用内部的分发。
_UIApplicationHandleEventQueue() 会把 IOHIDEvent 处理并包装成 UIEvent 进行处理或分发,其中包括识别 UIGesture/处理屏幕旋转/发送给 UIWindow 等。通常事件比如 UIButton 点击、touchesBegin/Move/End/Cancel 事件都是在这个回调中完成的。