底层原理 类的本质
复习一下IOS 底层原理 对象的本质–(1),可以看出来实例对象实际是上结构体,那么这个结构体是有类指针和成员变量组成的。
1 | //Person |
经过xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main64.cpp
编译之后其实Person
对象是:
1 | struct Person_IMPL { |
NSObject_IMPL
结构体:
1 | struct NSObject_IMPL { |
那么NSObject
在内存中包括
isa
指针- 其他成员变量
isa
地址就是instance
的地址,其他成员变量排在后边,也就是instance
的地址就是isa
的地址。
那么这个isa
指向的到底是什么呢?
请往下继续看:
先看下这段代码:
1 | NSObject *ob1=[[NSObject alloc]init]; |
这代码是输出了几个NSObject
的对象的类和NSObject
的类对象的地址,可以看到cl1==cl2
、cl3==cl4==cl5
。
Class的本质
我们知道不管是类对象还是元类对象,类型都是Class,class和mete-class的底层都是objc_class结构体的指针,内存中就是结构体。
1 | Class objectClass = [NSObject class]; |
点击class来到内部,可以发现
1 | typedef struct objc_class *Class; |
class
对象其实是指向objc_class的结构体,因此我们可以说类对象或元类对象在内存中其实就是objc_class结构体。
来到objc_class
内部,在源码中经常看到这段源码
1 | struct objc_class { |
这段代码明显是 已经OBJC2_UNAVAILABLE
,说明代码已经不在使用了。那么objc_class
结构体内部结构到底是什么呢?通过objc搜寻runtime
的内容可以看到objc_class
内部
1 | struct objc_class : objc_object { |
我们发现这个结构体继承 objc_object
并且结构体内有一些函数,因为这是c++
结构体,在c上做了扩展,因此结构体中可以包含函数。我们来到objc_object
内,截取部分代码
1 | struct objc_object { |
那么我们之前了解到的,类中存储的类的成员变量信息,方法列表,协议列表,截取class_rw_t
内部实现代码
1 | struct class_rw_t { |
而class_rw_t
是通过bits.data()
获取的,截取bits.data()
查看内部实现,而仅仅是bits&FAST_DATA_MASK
。
1 | class_rw_t* data() { |
而成员变量则是存储在class_ro_t
内部中的,我们来到class_ro_t
内部查看:
1 | struct class_ro_t { |
最后通过一张图总结一下:
那么我们来证明一下:
我们可以自定义一下一个和系统一样的结构体,那么我们当我们强制转化的时候,他们赋值会一一对应,此时我们就可以拿到结构体的内部的值。
下边代码是我们自定义的值:
1 | // |
这段代码亲测可用,直接复制自己新建.h
文件导入’main.m’即可,将main.m
改成main.mm
或者将其他某一个.m
改成.mm
运行就可以运行了。
那么我们再拿出来经典的那张图挨着分析isa
和superclass
的指向
instance 对象验证
使用 p/x
输出obj
16进制的地址,然后isa指针需要经过一次 & ISA_MASK操作之后才得到真正的地址。实施之后:
1 | //object |
从面的输出结果中我们可以发现instance对象中确实存储了isa指针和其成员变量,同时将instance对象的isa指针经过&运算之后计算出的地址确实是其相应类对象的内存地址。由此我们证明isa,superclass指向图中的1,2,3号线。
class 对象验证
接着我们来看class
对象,同样通过上一篇文章,我们明确class
对象中存储着isa
指针,superclass
指针,以及类的属性信息,类的成员变量信息,类的对象方法,和类的协议信息,而通过上面对object
源码的分析,我们知道这些信息存储在class
对象的class_rw_t
中,我们通过强制转化来窥探其中的内容
1 | //objectClass and objectMetaClass |
有此结果得知objectMetaClass==objectClass->isa==0x00007fff8e3ba0f0
,personClass->isa==personMetaClass==0x0000000100002440
,studentClass->isa==studentMetaClass==0x0000000100002490
。
由此我们证明isa,superclass指向图中,isa指针的4,5,6号线,以及superclass指针的7,8,9号线。
meta-class对象验证
最后我们来看meta-class
元类对象,上文提到meta-class
中存储着isa
指针,superclass
指针,以及类的类方法信息。同时我们知道meta-class
元类对象与class
类对象,具有相同的结构,只不过存储的信息不同,并且元类对象的isa
指针指向基类的元类对象,基类的元类对象的isa
指针指向自己。元类对象的superclass
指针指向其父类的元类对象,基类的元类对象的superclass
指针指向其类对象。
与class
对象相同,我们同样通过模拟对person
元类对象调用.data
函数,即对bits
进行&FAST_DATA_MASK(0x00007ffffffffff8UL)
运算,并转化为class_rw_t
。
1 | // objectMetaClass->superclass = 0x00007fff8e3ba140 NSObject |
由上面可以看出,studentMetaClass->isa
,personMetaClass->isa
,objectMetaClass->isa
结果mask
之后都是0x00007fff8e3ba0f0
,与p/x objectMetaClass
结果一致,则验证了13,14,15号线,studentMetaClass->superclass =0x0000000100002440
,personMetaClass = 0x0000000100002440
验证12号线,personMetaClass->isa=0x00007fff8e3ba0f0
和objectMetaClass = 0x00007fff8e3ba0f0
验证了11号线,objectMetaClass->superclass = 0x00007fff8e3ba140 NSObject
验证10号线。
总结:
对象的isa指向哪里?
- instance对象的isa指向class对象
- class对象的isa指向meta-class对象
- meta-class对象的isa指向基类的meta-class对象
- class和meta-class的内存结构一样的,只是值不一样
OC的类信息存放在哪里?
- 对象方法、属性、成员变量、协议信息存放在class对象中
- 类方法存放在meta-class对象中
- 成员变量具体值存放在instance对象中
资料下载
- 学习资料下载
- demo code
最怕一生碌碌无为,还安慰自己平凡可贵。
本文章之所以图片比较少,我觉得还是跟着代码敲一遍,印象比较深刻。
/