当前位置: 首页 > 面试题库 >

iOS里什么是响应链,它是怎么工作的?

贺浩壤
2023-03-14
本文向大家介绍iOS里什么是响应链,它是怎么工作的?相关面试题,主要包含被问及iOS里什么是响应链,它是怎么工作的?时的应答技巧和注意事项,需要的朋友参考一下

iOS里什么是响应链,它是怎么工作的?

第一反应就是,响应链就是响应链啊,由一串UIResponder对象链接,收到响应事件时由上往下传递,直到能响应事件为止。

但其中却大有文章...

1.由一串UIResponder对象链接 ?

我们知道UIResponder类里有个属性:

@property(nonatomic, readonly, nullable) UIResponder *nextResponder;

如果我们对响应链原理不清楚的话,会很容易的认为,这条链是由 nextResponder 指针连接起来的,在寻找响应者的时候是顺着这个指针找下去直到找到响应者为止的,但这是错误的认为。 举个例子: 现在我们有这样一个场景:

E0B0C758-8B7D-4B6A-85F3-72F3A174DCEA.png

AppDelegate上的Window上有一个UIViewController *ViewController, 然后在ViewController.view 上按顺序添加viewA和viewB,viewB稍微覆盖viewA一部分用来测试, 给viewA,viewB 分别添加点击手势tapA 和 tapB,然后把viewB.userInteractionEnabled = NO,让viewB不能响应点击。

然后我们点击重复的那块区域,会发现viewA响应了tap手势,执行了tapA的事件。 我们知道viewB设置了viewB.userInteractionEnabled = NO,不响应tap手势是正常的,但怎么会透过viewB,viewA响应了手势?

我们知道nextResponder指针指向的规则:

 

  • UIView
  • 如果 view 是一个 view controller 的 root view,nextResponder 是这个 view controller.
  • 如果 view 不是 view controller 的 root view,nextResponder 则是这个 view 的 superview
  • UIViewController
  • 如果 view controller 的 view 是 window 的 root view, view controller 的 nextResponder 是这个 window
  • 如果 view controller 是被其他 view controller presented调起来的,那么 view controller 的 nextResponder 就是发起调起的那个 view controller
  • UIWindow
  • window 的 nextResponder 是 UIApplication 对象.
  • UIApplication
  • UIApplication 对象的 nextResponder 是 app delegate, 但是 app delegate 必须是 UIResponder 对象,并且不能使 view ,view controller 或 UIApplication 对象他本身.

那么上述情况下,viewB所在的响应者链应该是: viewB -> ViewController.view -> ViewController -> Window -> Application 这种情况下怎么也轮不到viewA去响应啊。

所以,当有事件需要响应时,nextResponder 并不是链接响应链的那根绳子,响应链的工作方式另有别的方式

2. 那么响应链是如何工作,正确找到应该响应该事件的响应者的?

UIKit使用基于视图的hit-testing来确定touch事件发生的位置。具体解释就是,UIKit将touch的位置和视图层级中的view的边界进行了比较,UIView的方法 hitTest:withEvent: 在视图层级中进行,寻找包含指定touch的最深子视图。这个视图成为touch事件的第一个响应者。

说白了就是,当有touch事件来的时候,会从最下面的视图开始执行 hitTest:withEvent: ,如果符合成为响应者的条件,就会继续遍历它的 subviews 继续执行 hitTest:withEvent: ,直到找到最合适的view成为响应者。

这里要注意几个点:

  • 符合响应者的条件包括
  • touch事件的位置在响应者区域内
  • 响应者 hidden 属性不为 YES
  • 响应者 透明度 不是 0
  • 响应者 userInteractionEnabled 不为 NO
  • 遍历 subview 时,是从上往下顺序遍历的,即 view.subviews 的 lastObject 到 firstObject 的顺序,找到合适的响应者view,即停止遍历.

所以再回看上面的例子,当我们点击中间的重复区域时,流程其实是这样:

  • AppDelegate 的 window 收到事件,并开始执行 hitTest:withEvent: ,发现符合要求,开始遍历子view.
  • window 上只有 viewcontroller.view ,所以viewcontroller.view 开始执行 hitTest:withEvent: ,发现符合要求,开始遍历子view.
  • viewcontroller.view 有两个子view, viewA 和 viewB ,但是viewB 在 viewA 上边,所以先 viewB 执行 hitTest:withEvent: ,结果发现viewB 不符合要求,因为viewB 的 userInteractionEnabled 为 NO.
  • 接下来 viewA 执行 hitTest:withEvent: ,发现符合条件,并且viewA 也没有子view可去遍历,于是返回viewA.
  • viewA成了最终事件的响应者.

这样就完美解释了,最开始例子的响应状况.

那么如果 viewB 的 userInteractionEnabled 属性为YES的话,是怎么样的呢?

如果 viewB 的 userInteractionEnabled 属性为YES,上面流程的第三部就会发现viewB是符合要求的,而直接返回viewB作为最终响应者,中断子view的遍历,viewA都不会被遍历到了.

这就是响应链相关的点,如果有什么不对的请留言提示,然后有什么别的需要补充的我会及时补充~

 

 类似资料:
  • 本文向大家介绍什么是iOS的响应者链?相关面试题,主要包含被问及什么是iOS的响应者链?时的应答技巧和注意事项,需要的朋友参考一下 响应者链条:是由多个响应者对象连接起来的链条 作用:能很清楚的看见每个响应者之间的联系,并且可以让一个事件多个对象处理。 响应者对象:能处理事件的对象

  • 为了减少内核或跨进程内存泄漏(Spectre攻击),Linux内核1将使用一个新选项编译,引入到,以便通过所谓的retpoline执行间接调用。 这似乎是一个新发明的术语,因为谷歌搜索只是最近才使用(通常都是在2018年)。 1但是,它不是Linux特有的--类似或相同的构造似乎被用作其他操作系统缓解策略的一部分。

  • 本文向大家介绍什么是数组,它的作用是什么?,包括了什么是数组,它的作用是什么?的使用技巧和注意事项,需要的朋友参考一下 数组是一个数据容器,其中包含固定长度的同类数据类型的元素。它用于存储相同数据类型的元素。 示例 输出结果

  • 本文向大家介绍什么是icmp协议,它的作用是什么?相关面试题,主要包含被问及什么是icmp协议,它的作用是什么?时的应答技巧和注意事项,需要的朋友参考一下 考察点:ICMP协议   它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

  • 本文向大家介绍什么是React.forwardRef?它有什么作用?相关面试题,主要包含被问及什么是React.forwardRef?它有什么作用?时的应答技巧和注意事项,需要的朋友参考一下 React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特别有用: 转发 refs 到 DOM 组件

  • 本文向大家介绍什么是zoom?它有什么作用?相关面试题,主要包含被问及什么是zoom?它有什么作用?时的应答技巧和注意事项,需要的朋友参考一下 zoom是缩放比例,可以将元素进行缩放。 和css3中的transform:scale() 作用类似. 两者区别在于缩放的参照点不一样,zoom针对元素左上角,scale针对元素正中心