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个成员变量_imp
和key
,这不用多说确定是方法和关键值。那么咱们就能够猜测,是否是能根据key
获取到对应的IMP
,进行方法调用?至此也肯定了cache里缓存的是方法。 ui
bits
和 data
能够看到bits
是一个64位的数据段,那么里面存了什么数据呢? 3d
在bits
下面紧接了一个data
的声明,返回的正是bits
里面的数据。可是类型是class_rw_t
? 指针
class_rw_t
结构methods
方法、properties
属性、protocols
协议,都是咱们日常在声明类的时候能看到的,感受至关熟悉。可是里面还有一个class_ro_t
类型的成员变量ro
引发了个人注意 code
class_ro_t
结构ro
里也有方法、属性、协议,还有实例变量,这是为何呢? cdn
class_rw_t
LGPerson
以下
执行代码打印获取到LGPerson
类的结构,能够直接看到isa
和superClass
。可是怎么获取class_rw_t
和class_ro_t
呢?
经过isa
地址向右偏移32位能够获取到bits
输出methods
,看到数量为4,存储了咱们声明的sayHello
方法以及nickName
的setter、getter
方法,可是并无看到sayHappy
方法?
输出properties
能够看到咱们声明的nickName
属性,符合咱们的预期
输出protrols
,里面是空的,也符合预期
至此,对比LGPerson
文件咱们尚未看到sayHappy
方法和成员变量hobby
,猜想它们又被存储在哪里呢?来输出ro
看看
输出baseMethodList
能够看到里面的内容和rw
的methods
是同样的,没有sayHappy
方法
输出baseProperties
,很惋惜依旧没有找到hobby
输出ivars
,能够看到count
为2,单独输出之后咱们能够看到hobby
和_nickName
都在其中
sayHappy
方法到底去哪里了?sayHappy
和sayHello
区别在于 sayHello
是实例方法, sayHappy
是类方法。这说明了实例方法存储在类对象中,类方法不存储在类对象中。
那么类方法存在哪里呢?大胆猜想一下类方法会不会存在元类对象中呢?接下来去元类中寻找一下。
输出元类的方法列表
bits
和ro
数据重复问题bits
里面存储了方法列表、属性列表等成员变量,为何还须要ro
再存储一份?
objc_class
结构中的data()
方法能够返回bits
的信息,那么咱们即可以经过setData()
向上查找调用方看看class
赋值流程,也许就能解开这个问题。
找到编译期间执行的realizeClass
方法,这里应该就是最初的地方。 但这里并无对rw
里面的列表赋值,编译期间rw
的各个列表应该是空值!
那么rw的数据又是从哪里来的呢?这就涉及到了methodizeClass
方法,就是它向rw
中添加类的方法列表、协议列表、属性列表。
执行了methodizeClass
后ro
中的属性、对象方法,协议都添加到了rw
中。这样在class_rw_t
结构中能够拿到类的相关信息了。也就造成了如下结构:
虽然找到了实现,可是仍是不知道为何这么存呀。这就须要看看了realizeClass
在何时调用了。这个时候,prepare_load_methods
引发了个人注意
prepare_load_methods
是加载分类时会调用的方法,结合methodizeClass
咱们会发现分类添加的方法通通都会加入到rw
而不加入ro
。ro
保留着类最原始的数据,后续改变都没法侵入它!
至此,疑问已经解开,类结构已经解析完毕。
结论以下:
.h
文件声明属性会自动生成setter
、getter
、成员变量。ro
中,分类方法存在rw
中