iOS 类的数据结构

数据结构

Class 就是结构体 objc_class 数组

内部结构以下,须要注意的是objc_class继承自objc_object,那么里面就应该有一个isa缓存

参数名 类型 做用
isa Class isa指针,指向元类
superclass Class 父类
chache cache_t 方法缓存,大小由内部成员决定
bits class_data_bits_t 存储了一些数据
data class_rw_t 获取bits里存储的data

一、isa

具体请看 isa详解数据结构

二、superclass

看变量名就知道这是父类对象,不须要过多解释app

三、cache 方法缓存

cache顾名思义是缓存 post

参数名 类型 大小 做用
_buckets 数组 8字节 存储一个个结构体bucket_t
_mask mask_t,实际就是uint32_t 4字节 掩码
_occupied mask_t,实际就是uint32_t 4字节 已缓存的数量

接下来看bucket_t是什么,bucket_t有2个成员变量_impkey,这不用多说确定是方法和关键值。那么咱们就能够猜测,是否是能根据key获取到对应的IMP,进行方法调用?至此也肯定了cache里缓存的是方法。 ui

四、bitsdata

能够看到bits是一个64位的数据段,那么里面存了什么数据呢? 3d

bits下面紧接了一个data的声明,返回的正是bits里面的数据。可是类型是class_rw_t指针

4-1 class_rw_t 结构

methods方法、properties属性、protocols协议,都是咱们日常在声明类的时候能看到的,感受至关熟悉。可是里面还有一个class_ro_t类型的成员变量ro引发了个人注意 code

4-2 class_ro_t 结构

ro里也有方法、属性、协议,还有实例变量,这是为何呢? cdn

4-3 探索 class_rw_t

LGPerson以下

执行代码打印获取到LGPerson类的结构,能够直接看到isasuperClass。可是怎么获取class_rw_tclass_ro_t 呢?

经过isa地址向右偏移32位能够获取到bits

输出methods,看到数量为4,存储了咱们声明的sayHello方法以及nickNamesetter、getter方法,可是并无看到sayHappy方法?

输出properties能够看到咱们声明的nickName属性,符合咱们的预期

输出protrols,里面是空的,也符合预期

至此,对比LGPerson文件咱们尚未看到sayHappy方法和成员变量hobby,猜想它们又被存储在哪里呢?来输出ro看看

输出baseMethodList能够看到里面的内容和rwmethods是同样的,没有sayHappy方法

输出baseProperties,很惋惜依旧没有找到hobby

输出ivars,能够看到count为2,单独输出之后咱们能够看到hobby_nickName都在其中

4-四、类方法存储

sayHappy方法到底去哪里了?sayHappysayHello 区别在于 sayHello 是实例方法, sayHappy 是类方法。这说明了实例方法存储在类对象中,类方法不存储在类对象中。

那么类方法存在哪里呢?大胆猜想一下类方法会不会存在元类对象中呢?接下来去元类中寻找一下。

输出元类的方法列表

4-五、bitsro数据重复问题

bits里面存储了方法列表、属性列表等成员变量,为何还须要ro再存储一份?

objc_class结构中的data()方法能够返回bits的信息,那么咱们即可以经过setData()向上查找调用方看看class赋值流程,也许就能解开这个问题。

找到编译期间执行的realizeClass方法,这里应该就是最初的地方。 但这里并无对rw里面的列表赋值,编译期间rw的各个列表应该是空值!

那么rw的数据又是从哪里来的呢?这就涉及到了methodizeClass方法,就是它向rw中添加类的方法列表、协议列表、属性列表。

执行了methodizeClassro中的属性、对象方法,协议都添加到了rw中。这样在class_rw_t结构中能够拿到类的相关信息了。也就造成了如下结构:

虽然找到了实现,可是仍是不知道为何这么存呀。这就须要看看了realizeClass在何时调用了。这个时候,prepare_load_methods引发了个人注意

prepare_load_methods是加载分类时会调用的方法,结合methodizeClass咱们会发现分类添加的方法通通都会加入到rw而不加入roro保留着类最原始的数据,后续改变都没法侵入它!

总结

至此,疑问已经解开,类结构已经解析完毕。

结论以下:

  • .h文件声明属性会自动生成settergetter、成员变量。
  • 实例方法存在类中,类方法存在元类中
  • 原始方法会存在ro中,分类方法存在rw
相关文章
相关标签/搜索