前言
在上篇文章iOS底层探索——对象的本质&isa分析中,我们知道了对象里面含有一个叫做isa
的指针,并且通过isa
指针,从对象找到了他所属的类,今天我们就来探索一下关于类的秘密。
类的isa
元类
我们知道,对象的isa
指向的是类,那么类里面是不是也会有同样的东西的,他指向的又是什么呢?带着问题,我们开始我们的探索
我们使用对象的探索思维,同样打印出DMPerson
类的内容,对第一个八位我们猜想他是不是类似isa
的结构呢,使用掩码进行运算
我们发现计算出来的地址0x0000000100008200
打印出来是DMPerson
。我们再打印DMPerson
类的地址0x0000000100008228
,这两个地址并不一样,但是都打印出了DMPerson
,那么类是不是也跟对象一样,每个对象都有不同的地址呢?
void dmTestClassNum(void){
Class class1 = [DMPerson class];
Class class2 = [DMPerson alloc].class;
Class class3 = object_getClass([DMPerson alloc]);
Class class4 = [DMPerson alloc].class;
NSLog(@"\nclass1:%p\nclass2:%p\nclass3:%p\nclass4:%p",class1,class2,class3,class4);
}
复制代码
我们通过不同的方式,多创建几个类,并且打印出他的地址,其结果如下
我们发现所有的类打印输出的结果都是0x0000000100008228
这个地址,说明同一个类,在内存中只有一个地址。那么0x0000000100008200
这个地址所代表的的又是什么呢?下面我们通过辅助软件MachOView
来看看我们符号表里面的内容。
由于我们的工程只有DMPerson
这一个类,所以在__DATA__objc_classrefs
这个结构下,只有一行。继续探索
在全部的符号表中,搜索class这个关键字,我们神奇的发现,除了_OBJC_CLASS_$_DMPerson
以外,还有一个叫做_OBJC_METACLASS_$_DMPerson
的东西,这就是我们要找的0x0000000100008200
中存的内容,我们称之为元类
。元类
并不是我们主动生成的,是系统在编译期自动生成的,所以我们可以得出下面一个结论
对象的isa指向类,而类的isa指向元类,类可以看做是元类的一个对象,我们称之为类对象
。
根元类
在上面的探索中,我们引出了一个新的概念元类
,类对象
的isa
指向的就是元类
,那么元类有没有isa
呢?如果有,他的isa
指向的又是什么呢?
按照类
的探索顺序,我们对元类进行同样的操作,发现元类
也存在isa
,他指向的是NSObject
,而这个地址与NSObject
类的地址同样不同。我们再来打印看看NSObject
的元类是什么呢?
我们发现NSObject
的isa
指向与DMPerson
的元类的isa
指向一样。由于NSObject
是OC中所有类的根类,所以我们又把NSObject
的元类,称之为根源类
。
那么上面的图,就进化为了这样:
isa的走位图
我们继续猜想,既然对象
,类
,元类
都有isa,那么根元类
有没有isa呢?他指向什么呢?
我们用同样的流程对根源类
进行了探索,发现根源类
的isa
指向了他自己,所以整个isa
的查找流程就形成了闭环,我们继续将上面的图进行升级,得到了最终的
类的superclass
在之前的探索中,我们知道,类在底层中实际上是objc_class
这个结构,那么我们就来看看这个结构的组成
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
……其他的方法……
}
复制代码
这里省略的部分方法,我们暂时先不研究,我们发现在这个结构里面有几个东西
- Class isa:指向元类的指针
- Class superclass:指向父类的指针
- cache_t cache:缓存
- class_data_bits_t bits:类存储信息的地方
isa指针
在上面我们已经进行过探索了,我们接下来探索一下superclass指针
。
我们在之前的代码中添加了一个叫做DMWorker
的类,继承自DMPerson
。
@interface DMWorker : DMPerson
- (void)saygood;
@end
@implementation DMWorker
- (void)saygood
{
NSLog(@"good");
}
@end
复制代码
现在我们来看看他的继承关系
以图来实例的话
从上面的探索中我们知道,类的isa
指向元类
,那么元类
是不是也有这样的继承关系呢?我们继续往下探索
从图中的探索我们可以看得,元类
也同样存在跟类一样的继承关系,最后到NSObject
元类的父类则指向了NSObject
本身,那么我们上面的那张图就可能更新为
总结
上面的isa的图和继承的图,苹果有一张经典的图来表示他们
相信大家应该都看过这个图,经过我们之前的分析,对这张图的理解,应该已经更加深刻了。