美文网首页
从 Cocoa 到 响应者链

从 Cocoa 到 响应者链

作者: 柯浩然 | 来源:发表于2018-01-26 17:35 被阅读36次
    • “Cocoa” 是创建 Mac OS 和 iOS 程序的原生面向对象 API。是一个框架的集合,包含众多子框架,其中最重要的就属 Foundation 和 UIKit。这两个框架在系统中的位置如下图:
    • 其实 iOS 程序是由大量的对象构成。而这些对象的根对象都是 NSObject。NSObject 就存在于 Foundation 中。具体的类结构如下:

    通常我们把他们分成几类:
    1.值对象:NSValue、NSNumber、NSString等
    2.集合:NSArray、NSDictionary、NSSet等
    3.操作系统服务:文件系统:NSFileManager等;URL:NSURLSession等;进程通讯:NSPipe(一种进程间的单向通讯通道)等
    4.线程和子任务:NSThread、NSTask(分出一个子进程执行其他工作)
    4.通知:NSNotification等
    5.归档与序列化:NSArchive
    6.表达式与条件判断:NSScanner、
    7.Objective-C 语言服务:

    • NSProxy是另外的一个基类。
      可以用这个类在 OC 中模拟实现多继承。因为它可以实现消息转发。
      具体可看http://ios.jobbole.com/87856/
    UIKit 框架

    应用程序可以通过三种方式使用 UIKit 创建界面
    1.使用用户界面工具(Interface Bulider)从对象库里拖拽使用
    2.用代码创建
    3.通过继承或间接继承 UIView 类实现自定义实现用户界面


    图中可以看到,UIResponder 类是图中最大分支的类,UIResponder 为处理响应事件和响应链定义了界面和默认行为。

    • 当用户用手指滚动列表或用虚拟键盘输入时,UIKit 就生成事件传送给 UIResponder 响应链,直到链中有对象处理这个事件。
    响应链
    • iOS 中点击事件从分发传递到响应的完整流程
    • 包含事件的传递和事件的响应

    事件的传递包含 UIView 中的两个方法

    事件的传递其实就是在事件产生与分发之后寻找最优响应视图的过程
    事件的传递流程

    1.触摸屏幕生成事件 UIEvent 并存入 UIApplication 事件队列中,并且在整个视图结构中自上而下进行分发
    2.各层接收到事件进行最优响应视图的查询(逆序遍历 subviews,优化查找速度,毕竟后 add 的 view 在上易于命中)


    Note:
    如果在 hitTest && pointInside 过程中查询到最优响应视图则对后续 subviews 的查询就会停止。

    • 视图中的查找
      1.调用 hitTest 进行最优响应视图查询
      hidden == YES
      userInteractionEnabled = NO
      alpha < 0.01
      以上三种情况会使方法返回 nil,即当前视图下没有最优响应视图。
      2.hitTest 方法内部会调用 pointIinside 方法对点击点是否在视图 bounds 上进行判断。如果不是,返回nil,如果是,则进行步骤3
      3 逆序遍历当前视图的 subviews ,进行上述 1,2步骤寻找最优响应视图。
    事件的响应流程
    下面来一张苹果官方的图片

    响应链其实是由一个个 UIResponder 的子类构成的,UIResponder 是系统一个负责接收和处理事件的类

    响应流程
    1.首先已确定最优响应视图
    2.查看当前视图是否可以响应事件,如果能,事件传递终止。如果不能,事件传递给视图的 nextResponsed 也就是通常的 superview 进行响应
    3.如果事件上报至 UIWindow 也无法响应,则把事件上报给 UIApplication
    4.如果事件继续上报至 UIApplication 也无法响应,就把事件继续上报给他的代理 UIAppDelegate,要说明的是,这个代理不属于响应者链并且是 UIResponder 的子类。
    5.如果事件最终未被响应则会被抛弃

    Note:
    并非所有的 nextResponsed 都是 superView。比如:VC 的根视图的 self.view 的 nextResponsed 是 VC。如果 VC 是 UIWindow 的根控制器,那么他的 nextResponsed 就是 UIWindow。如果 VC 是由另一个 VC present 出来的,那么他的 nextResponsed是执行 present 的那个 VC 。

    从 nextResponder 可以看出,所有的响应者都是在查找中返回可响应点击的视图。因此可以推测出,UIApplication 维护这一个 响应者栈,当 pointInSide:event:返回 YES 的时候,响应者入栈。


    栈顶的响应者最为最优先处理事件的对象,假设 Aview 不处理,那么出栈,移交给 UIView,以此下去,直到事件得到处理或者被系统摒弃为止。controller 是响应者的例外,即使没有 pointInside 方法,依旧能够成为 UIView 的下一个响应者。
    本文参考:
    https://zhuanlan.zhihu.com/p/31056987
    http://www.cocoachina.com/ios/20160113/14896.html
    http://blog.csdn.net/fengsh998/article/details/8842885

    相关文章

      网友评论

          本文标题:从 Cocoa 到 响应者链

          本文链接:https://www.haomeiwen.com/subject/jtlwaxtx.html