引言
接上篇文章003-OC对象原理探究 - isa 和 nonpointer,本文将通过实际代码演示,探究如何探究isa
的走向,以及对象的继承关系。
ISA走位探究
一、拿到ISA_MASK(isa掩码)
上期我们说道苹果对isa的优化,获取对象,是根据isa的mask
来得到的,那么我们先把ISA_MASK
取出
__arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
__x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
ULL
表示unsigned long long
二、代码实操
我们新建一个类QLDog
,创建dog
对象,打上断点,进入lldb
调试模式
在控制台输入
1、
p/x dog
,得到dog对象的地址。(p/x
为lldb
指令,请自行google搜索lldb
常用指令学习)
2、接着输入
x/4gx 0x00006000031385a0
,得到dog的内存结构
3、此时猜想
0x0000000109f35360
是不是我们对象的isa
?那么我们只需要与isa_mask
做一次&
即可
4、执行指令
p/x 0x0000000109f35360 & 0x00007ffffffffff8
,得到(long) $2 = 0x0000000109f35360
,接着po 0x0000000109f35360
可得到如下结果:
isa
-------分割线-------
5、我们继续探索,继续调试
x/4gx 0x0000000109f35360
的内存结构如下:
6、我们猜想,
0x0000000109f35338
是否也为0x0000000109f35360
的isa
呢?我们重复与isa_mask
的&
操作:
7、很惊奇的发现,最终打印的也是
QLDog
。但是两个QLDog
的地址不一样,分别是0x0000000109f35360
和0x0000000109f35338
,这是为什么呢?按照这个猜想,类对象在内存中是否可以无限开辟?也就是类对象是否是不只一个类。
验证
测试代码:
Class cls1 = [QLDog class];
Class cls2 = [QLDog alloc].class;
Class cls3 = object_getClass([QLDog alloc]);
Class cls4 = [QLDog alloc].class;
NSLog(@"\n%p--\n%p--\n%p--\n%p--",cls1,cls2,cls3,cls4);
运行后,打印结果如下:
打印结果的地址与
dog
对象一致,都是0x00006000031385a0
,证明了我们前面的猜想:0x00006000031385a0
为类QLDog
,而0x0000000109f35338
不是类。那它是什么东西?
接下来我借助一个工具
来分析编译后的代码是什么样子的。
工程中,products文件夹内的可执行文件(.app或者macho)show in finder,找到可执行文件后,直接拖入
MachOView
工具中(.app要显示包内容,里面黑色的可执行文件就是)。
拖入
MachOView
后,找到Symbol table
下的Symbols
,搜索QLDog
可看到我们的类:
其中有几个value是系统生成的,我们这里只需关注
_OBJC_METACLASS_$_QLDog
即可。metaclass
是元类的意思。由此结合上面的探索可知,我们探索对象dog的内存结构,得到对象的isa,&上isa_mask
得到类QLDog,接着对其内存窥探,得到类的isa,接着&上isa_mask
得到一个元类
。
到此为止,我们的
isa
探索走向为:对象isa
---类isa
---元类isa
。
我们重复以上的p/x
和x/4gx
调试指令,最终得到
我们对
NSObject
类的内存进行解析:
由此可总结
isa
的走向:(请与继承链区分)
解释:
1、任何的对象的isa,会找到自己的类
2、自己的类的isa,会找到自己的类的元类
3、元类的isa,会找到根元类
4、根元类的isa最终找到自己
继承链探索
对象的继承
设计代码如下:
QLDog *dog = [QLDog alloc];
Class dogSuperClass = [dog superclass];
Class superClass1 = [dogSuperClass superclass];
Class superClass2 = [superClass1 superclass];
Class superClass3 = [superClass2 superclass];
Class superClass4 = [superClass3 superclass];
NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",dog,dog,dogSuperClass,dogSuperClass,superClass1,superClass1,superClass2,superClass2,superClass3,superClass3,superClass4,superClass4);
打印结果如下:
由此可得对象继承链为:
dog——>person——>NSObject——>nil
类的继承
设计代码如下:
Class dogClass = [QLDog class];
Class superClass5 = [dogClass superclass];
Class superClass6 = [superClass5 superclass];
Class superClass7 = [superClass6 superclass];
Class superClass8 = [superClass7 superclass];
Class superClass9 = [superClass8 superclass];
NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",dogClass,dogClass,superClass5,superClass5,superClass6,superClass6,superClass7,superClass7,superClass8,superClass8,superClass9,superClass9);
打印结果如下
由此可得类继承链为:
QLDog——>QLPerson——>NSObject——>nil
元类的继承
设计代码如下:
Class metaClass1 = object_getClass(dogClass);
Class metaClass2 = class_getSuperclass(metaClass1);
Class metaClass3 = class_getSuperclass(metaClass2);
Class metaClass4 = class_getSuperclass(metaClass3);
Class metaClass5 = class_getSuperclass(metaClass4);
Class metaClass6 = class_getSuperclass(metaClass5);
NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",metaClass1,metaClass1,metaClass2,metaClass2,metaClass3,metaClass3,metaClass4,metaClass4,metaClass5,metaClass5,metaClass6,metaClass6);
打印结果如下:
由此可得元类继承链为:QLDog——>QLPerson——>NSObject——>NSObject——>nil
注意此处两个NSObject地址不一样。
NSObject特殊情况
设计代码如下:
//NSObject实例对象
NSObject *object1 = [NSObject alloc];
//NSObject类
Class objClass = object_getClass(object1);
//NSObject元类
Class objMetaClass = object_getClass(objClass);
//NSObject根元类
Class rootMetaClass = object_getClass(objMetaClass);
//NSObject根元类的根元类
Class rootRootMetaClass = object_getClass(rootMetaClass);
NSLog(@"\n%@--%p 实例对象 \n%@--%p 类 \n%@--%p 元类 \n%@--%p 根元类 \n%@--%p 根根元类 ",object1,object1,objClass,objClass,objMetaClass,objMetaClass,rootMetaClass,rootMetaClass,rootRootMetaClass,rootRootMetaClass);
// NSObject根类获取父类
Class objectSuperClass = class_getSuperclass(objClass);
NSLog(@"%@---%p",objectSuperClass,objectSuperClass);
// NSObject根元类获取父类
Class objectSuperMetaClass = class_getSuperclass(objMetaClass);
NSLog(@"%@---%p",objectSuperMetaClass,objectSuperMetaClass);
打印结果如下:
测试结果可得结论:
1、
根类
父类为nil
2、
根元类
父类为 NSObject类
3、所以
万物皆来自NSObject
继承图:箭头为superclass
总结
综合isa走位链以及类的继承链,我们引入苹果官方的isa/superclass链图
2021年06月21日16:09:39
——杭州