OC语言

iOS Runtime学习笔记数据结构篇

2019-01-18  本文已影响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指针到它的元类方法中进行方法查找。

对象 类 元类之间关系

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数据结构相关面试题

上一篇下一篇

猜你喜欢

热点阅读