面试题记录 - Runtime

eggmanQQQ
  • objc-runtime source cide
  • objc4 source code
  • Apple Runtim Doc
    • *
  • Runtime: 即运行时,是一套底层的 C 语言 API,是 iOS 系统的核心之一。开发者在编码过程中,可以给任意一个对象发送消息,在编译阶段只是确定了要向接收者发送这条消息,而接受者将要如何响应和处理这条消息,那就要看运行时来决定了。
  • 结构模型

    1. runtime 的内存模型

      • isa

        • 类型为 isa_t() 的结构体
        • 从结构上来说, isa_t() 的本质是 union 类型, 与 struct 相比, union 可以节省更多的空间.

          • union 的定义是它使几个不同类型的变量共占一段内存, 占用空间由结构体里占最大字节的成员类型决定
          • union 中变量可以相互覆盖, 使几个不同的变量存放到同一段内存单元中
        • 作用上来说, 还是类似于指针, 实例的 isa 指向类, 类的 isa 指向元类(metaclass)
      • 对象

        • 是 objc_object 是 C 语言结构体, 只包含 isa_t 类型的结构体 isa.
        • 实际开发中被 typedef 为 id 类型
        • 继承于 objc_object, 所以类也是对象的一种
        • 定义了可以接受消息的方法名
        • 除 isa 外, 还有 3 个成员变量

          • superclass 父类的指针
          • cache 方法缓存
          • bits 实例方法列表
      • metaclass

        • 存储着一个类的所有类方法
        • 每个类都会有 metaclass.
      • 对象-类-metaclass

        • 对象的 isa 指向类
        • 类的 isa 指向 metaclass
        • metaclass 的 isa 都指向根类, 即 Root class
        • 类的 superclass 指向父类
        • metaclass 的 superclass 指向父类的 metaclass
        • Root class 的 superclass 指向 NSObject
        • 对象的 isa 不断查找, 可以找到根元类(Root metaclass)
        • 根元类的 superclass 指向 NSObject
    2. 方法调用(消息发送)

      • 一个对象的实例方法被调用时, 会通过 isa 找到相应的类, 然后在该类的 class_data_bits_t bits 中查找方法.

        • class_data_bits_t 是指向了类对象的数据区域的机构体
      • objc_object 对象的实例方法调用时, 通过对象的 isa 在类中获取方法的实现
      • objc_class 对象的类方法调用时, 通过类的 isa 在 metaclass 中获取方法的实现
      • 如果该类没有一个方法的实现, 则向父类继续查找
      • _objc_msgSend 流程

        1. 判断消息接受者是否为 nil 或者使用使用了 tagPointer
        2. 根据消息接受者的 isa 找到

          1. 消息接受者是类, isa 找到元类 metaclass
          2. 消息接收者是实例, isa 找到类
        3. 进入 CacheLookup 流程, 寻找方法缓存

          1. 缓存有记录则直接调用

            1. 调用 TailCallCechedImp 验证 IMP 有效性
          2. 缓存没记录则进入 __objc_msgSend_uncached 流程
        4. __objc_msgSend_uncached 中调用 __class_lookupMethodAndLoadCache3 方法, 该方法会返回 IMP 对象, 里面再调用了 lookUpImpOrForward 方法

          1. 会再次从类的方法缓存中查找
          2. 在类的方法列表中查找, 成功则写入缓存并调用, 否则
          3. 从父类的缓存中查找, 找不到则从父类的方法列表查找, 如此循环知道基类(NSObject)
          4. 基类还没有找到方法, 进入动态方法解析流程(resolveInstanceMethod | resolveClassMethod)
          5. 动态解析失败, 则进入消息转发流程(forwardingTargetForSelector | forewordInvocation | methodSignatureForSelector)
          6. 消息转发失败, IMP=nil, crash
    3. 为什么要设计 metaclass

      • (mac重启后记录缺失, 后补)
阅读 720
1 声望
1 粉丝
0 条评论
你知道吗?

1 声望
1 粉丝
文章目录
宣传栏