响应链:
用户点击屏幕产生事件 -> UIApplication 开始事件分发
-> UIWindow-> Subviews
UIWindow的子视图会内部递归调用
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
如果上面的方法返回视图就会调用这个方法
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
- 当view的userInteractionEnabled为NO、hidden为YES或alpha<=0.1时,也不会打印pointInside方法。因此可以推断出在hitTest方法内部会判断如果这些条件一个成立则会返回nil,也不会调用pointInside方法。
- pointInside只是在执行hitTest时,会在hitTest内部调用的一个方法。也就是说pointInside是hitTest的辅助方法。
- 通过重写目标控件的
pointInside: withEvent:
方法可以扩大响应范围
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"%@ -- pointInside",self.class);
CGRect bounds = self.bounds;
//若原热区小于200x200,则放大热区,否则保持原大小不变
//一般热区范围为40x40 ,此处200是为了便于检测
CGFloat widthDelta = MAX(200 - bounds.size.width, 0);
CGFloat heightDelta = MAX(200 - bounds.size.height, 0);
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
return CGRectContainsPoint(bounds, point);
}
响应链事件是由上至下的;触摸事件是由由下至上的;
分类关联对象
- objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)函数
1.系统用一个全局的AssociationsManager
去管理一张全局的AssociationsHashMap
表,表中key是disguised_ptr_t
(由object
转化而来),value
是AssociationsHashMap
2.AssociationsHashMap
中key
就是上面函数中的const void *key
,而value
是ObjcAssociation
3.ObjcAssociation
内包含着policy
,和具体的value
原理图
所以关联对象并不是放在了原来的对象里面,而是系统维护了一个全局的map用来存放每一个对象及其对应关联属性表格。