面试题答案
一键面试优化思路
- 减少响应链长度:避免不必要的视图嵌套,尽量扁平化视图结构。复杂的多层嵌套会使事件传递经过更多视图,增加响应时间。
- 提前判断处理:在视图层级较高的视图中提前判断是否能处理事件,若不能则快速传递给合适的视图,减少不必要的传递过程。
- 缓存处理:对于一些经常处理事件的视图,缓存相关的判断逻辑和处理函数,避免重复计算。
实现方法
- 简化视图结构
- 分析UI布局,合并一些功能相近且嵌套较深的视图,例如将一些装饰性且无交互的视图合并为一个自定义视图。
- 使用
UIStackView
等布局方式,在保持布局灵活性的同时,简化视图层级关系。
- 重写响应方法
- 在视图中重写
hitTest:withEvent:
方法,在这个方法中提前判断触摸点是否在本视图需要处理的范围内。如果不在,直接返回能处理该事件的子视图,减少事件在响应链上不必要的传递。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (!self.userInteractionEnabled || self.hidden || self.alpha <= 0.01) { return nil; } if (CGRectContainsPoint(self.bounds, point)) { for (UIView *subview in self.subviews.reverseObjectEnumerator) { CGPoint subPoint = [self convertPoint:point toView:subview]; UIView *result = [subview hitTest:subPoint withEvent:event]; if (result) { return result; } } return self; } return nil; }
- 在
UIViewController
中重写pointInside:withEvent:
方法,类似地提前判断触摸点是否在当前视图控制器管理的视图范围内,若不在则快速返回NO
,避免事件进入本视图控制器的视图响应链。
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if (!self.view.userInteractionEnabled || self.view.hidden || self.view.alpha <= 0.01) { return NO; } return CGRectContainsPoint(self.view.bounds, point); }
- 在视图中重写
- 缓存机制
- 对于一些固定判断逻辑的视图,例如一个特定区域总是需要处理某类事件的视图,可以在初始化时计算好该区域的
CGRect
等信息并缓存起来。在处理事件时直接使用缓存信息进行判断,而不是每次重新计算。 - 对于经常调用的事件处理函数,可以通过
Method Swizzling
等技术缓存函数指针,提高函数调用效率。但要注意Method Swizzling
的使用场景和副作用,确保不影响其他功能。
- 对于一些固定判断逻辑的视图,例如一个特定区域总是需要处理某类事件的视图,可以在初始化时计算好该区域的