iOS开发-触摸事件传递Touch Event

本文详细介绍了iOS中触摸事件从屏幕点击到事件响应的整个流程,包括事件的生成、处理、包装和分发。重点讲解了hitTest方法在事件传递中的作用,如何确定响应者以及响应链的工作原理。同时,文中还提到了在Mac开发中事件传递的差异,加深了对iOS触摸事件传递机制的理解。
摘要由CSDN通过智能技术生成

大概流程

iphone屏幕点击,到事件响应大概经历了这几个过程

苹果注册了一个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事件都是在这个回调中完成的。

  1. 接收到屏幕点击事件后,会包装成Source0类型的Event事件添加到Main Runloop
  2. 主线程执行Source0,并开始事件传递,确认响应者,即由UIApplication传到UIWindow,再由父视图传子视图,即由下至上传递,通过pointInside:withEvent:判断是否在点击范围(在范围内则返回YES,反之)和hitTest:withEvent:方法获得最终处理该事件的View(返回值为UIView)
  3. 确认响应者之后,开始响应链,触发touchesBegan等触摸事件,通过由nextResponder属性传递,一级一级往下传递,一般来说nextResponder会设置成父视图,所以一般都是由上至下

注意事项:

  1. 点击事件类型为Source0,由Runloop源码中得知,详细为__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
  2. 响应者指的是继承UIResponser的对象,包括最常见的UIViewUIViewController甚至是UIApplication,所以我们的UIView和UIViewController都是作为响应事件的载体
  3. 事件传递的线路和响应链的线路可能不一致
  4. pointInside:withEvent:仅仅判断是否在点击范围内,真正的判断是谁处理Event是由hitTest:withEvent:返回的UIView

Source0

根据Runloop源码,处理的事件有下列6种

// main  dispatch queue
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__

// __CFRunLoopDoObservers
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__

// __CFRunLoopDoBlocks
__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__

// __CFRunLoopDoSources0
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__

// __CFRunLoopDoSource1
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__

// __CFRunLoopDoTimers
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__

通过触摸事件中断点我们得知

#pragma mark - 触摸事件
//__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
   
    NSLog(@"来了,老弟!!!");//断点5
}

断点5的堆栈信息如下:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000102354b14 RunloopSourceCode`-[ViewController touchesBegan:withEvent:](self=0x0000000141d117e0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00000002819546c0) at ViewController.m:52
    frame #1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值