美文网首页OC语言
iOS Runtime学习笔记数据结构篇

iOS Runtime学习笔记数据结构篇

作者: 人魔七七 | 来源:发表于2019-01-18 10:04 被阅读28次

    前言

    几个数据结构概念

    objc_object

    objc_class

    objc_class继承于objc_object。所以在objc_class中也会包含isa_t类型的结构体isa。至此,可以得出结论:Objective-C 中类也是一个对象。在objc_class中,除了isa之外,还有3个成员变量,一个是父类的指针,一个是方法缓存,最后一个这个类的实例方法链表。

    isa指针

    什么作用呢?

    注意:
    isa指针:
    是一个共用体类型。
    一般是32位或者64位。
    分为两种:
    1)指针型isa:代表Class的地址。
    2)非指针型isa:比如64位其中的30+、40+位代表Class地址,就可以寻找到所有Class,就够用了。其余位则表示其它相关内容达到节省内存的目的。这也是有两种isa的初衷。

    isa指向

    注意:
    1)关于对象,也就是实例,在runtime中对应于objc_object,它其中有一个isa指针,指向对应的类。
    2)关于类对象,Class代表objc_Class,继承objc_object,自然也是有isa指针,指向其元类对象MetaClass。
    所以,在进行方法调用的时候,实例会通过isa指针就会去类中进行查找;类对象则会通过isa指针到它的元类方法中进行方法查找。

    对象 类 元类之间关系

    • 图中实线是 super_class指针,虚线是isa指针。

    • Root class (class)其实就是NSObject,NSObject是没有超类的,所以Root class(class)的superclass指向nil。

    • 每个Class都有一个isa指针指向唯一的Meta class

    • Root class(meta)的superclass指向Root class(class),也就是NSObject,形成一个回路。

    • 每个Meta class的isa指针都指向Root class (meta)。

    cache_t


    cache_t是一个数组,每个元素都是一个bucket_t,其中包含两个成员变量,一个是key,即selector;另外一个IMP是一个无类型的函数指针。

    比如给出一个key,就可以通过哈希查找算法定位key对应的这个key位于数组当中的位置,然后通过提取IMP来调用函数。

    Cache的作用主要是为了优化方法调用的性能。当对象receiver调用方法message时,首先根据对象receiver的isa指针查找到它对应的类,然后在类的methodLists中搜索方法,如果没有找到,就使用super_class指针到父类中的methodLists查找,一旦找到就调用方法。如果没有找到,有可能消息转发,也可能忽略它。但这样查找方式效率太低,因为往往一个类大概只有20%的方法经常被调用,占总调用次数的80%。所以使用Cache来缓存经常调用的方法,当调用方法时,优先在Cache查找,如果没有找到,再到methodLists查找。

    注意:局部性原理
    在调用方法的时候,往往调用的都是调用频次最高的,这时把这些方法放在缓存中,下次命中的概率会高一些。

    class_data_bits_t

    是objc_class中的结构。
    class_rw_t代表了类相关的读写信息,比如关于给类添加的一些分类方法、属性、协议,也对class_ro_t进行了封装。
    class_ro_t代表了类相关的只读信息

    class_rw_t

    class_ro_t

    methodList是一维数组(由于该结构是只读的,不允许添加新元素),所以存放的是原有的一些方法。

    注意:

    1. 类在内存中的位置是在编译期间决定的,在之后修改代码,也不会改变内存中的位置。

    2. 类的方法、属性以及协议在编译期间存放到了“错误”的位置,直到 realizeClass 执行之后,才放到了 class_rw_t 指向的只读区域 class_ro_t,这样我们即可以在运行时为 class_rw_t 添加方法,也不会影响类的只读结构。

    3. 在 class_ro_t 中的属性在运行期间就不能改变了,再添加方法时,会修改 class_rw_t 中的 methods 列表,而不是 class_ro_t 中的 baseMethods,对于方法的添加会在之后的文章中分析。

    method_t

    types Encoding技术

    下面代码第一项和第二项参数对应上图的id 和 SEL
    id objc_msgSend(id self, SEL op, ...);

    总结:

    参考链接:

    神经病院 Objective-C Runtime 入院第一天—— isa 和 Class
    从 NSObject 的初始化了解 isa
    Runtime数据结构相关面试题

    相关文章

      网友评论

        本文标题:iOS Runtime学习笔记数据结构篇

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