面试题答案
一键面试1. iOS触摸事件响应链传递过程
- 事件产生:当用户触摸屏幕时,系统会生成一个触摸事件(
UIEvent
),这个事件包含了触摸的相关信息,例如触摸点的位置、触摸的阶段等。 - 事件传递给应用程序:系统将触摸事件传递给应用程序的主事件队列(
UIApplication
的事件队列)。 - 事件从
UIApplication
传递到UIWindow
:UIApplication
从事件队列中取出事件,并将其传递给应用程序的主窗口(UIWindow
)。 - 寻找初始响应者:
UIWindow
开始寻找合适的初始响应者来处理这个事件。它会从视图层次结构的最顶层视图开始,通过调用视图的hitTest:withEvent:
方法来寻找能够响应触摸事件的视图。hitTest:withEvent:
方法首先会检查当前视图是否隐藏(hidden == YES
)、是否不透明(alpha <= 0.01
)或者是否禁用(userInteractionEnabled == NO
),如果满足任何一个条件,则返回nil
,表示该视图不能成为初始响应者。- 否则,它会从后往前遍历当前视图的所有子视图,对每个子视图调用
pointInside:withEvent:
方法,判断触摸点是否在子视图的范围内。如果某个子视图返回YES
,则会对该子视图调用hitTest:withEvent:
方法,递归寻找更合适的响应者。如果所有子视图都不满足条件,则当前视图就是初始响应者。
- 事件沿着响应链传递:一旦找到初始响应者,事件就会沿着响应链向上传递。响应链由初始响应者开始,依次是它的父视图、父视图的父视图,直到
UIWindow
,再到UIApplication
。 - 事件处理:在响应链传递过程中,每个响应者都有机会处理事件。如果某个响应者处理了事件,事件传递就会停止;如果没有响应者处理事件,事件最终会传递到
UIApplication
,如果UIApplication
也不处理,事件就会被丢弃。
2. 优化策略
- 减少视图层级:
- 复杂的视图层级会增加响应链的长度,从而影响性能。尽量简化视图结构,合并不必要的视图,避免过多的嵌套视图。例如,使用
UIScrollView
或UICollectionView
来代替多个独立的视图容器,以减少视图层级。
- 复杂的视图层级会增加响应链的长度,从而影响性能。尽量简化视图结构,合并不必要的视图,避免过多的嵌套视图。例如,使用
- 提前判断是否需要处理事件:
- 在视图的
hitTest:withEvent:
方法中,可以提前进行一些逻辑判断,避免不必要的子视图遍历。例如,如果某个视图只有在特定条件下才需要响应事件,可以在hitTest:withEvent:
方法中先检查这些条件,不满足条件时直接返回nil
,减少不必要的递归查找。
- 在视图的
- 延迟加载视图:
- 对于一些不常用或者在界面加载时不需要立即显示的视图,可以采用延迟加载的方式。这样在初始加载时,响应链中的视图数量会减少,提高性能。当需要显示这些视图时,再进行加载并添加到视图层级中。
- 使用手势识别器:
- 手势识别器(
UIGestureRecognizer
)提供了一种更方便和高效的方式来处理触摸事件。它可以在视图层级的较高层次捕获事件,避免事件在响应链中不必要的传递。例如,对于常见的点击、滑动等操作,可以直接使用系统提供的手势识别器,而不是依赖响应链传递事件到具体的视图进行处理。
- 手势识别器(
- 缓存响应者:
- 如果某些视图的响应者状态很少改变,可以考虑缓存它们。例如,对于一些固定的视图结构,可以在初始化时计算并缓存每个视图的初始响应者,避免每次事件传递时都重新进行查找。
- 优化主线程任务:
- 响应链的处理通常在主线程进行,因此要确保主线程的性能。避免在主线程执行复杂的计算、网络请求等耗时操作,将这些任务放到后台线程处理,保证触摸事件的响应能够及时进行。