这篇文章继 Runtime系列(引文)之后,仍然是一篇引导文,主讲类与元类。如果你读过 Runtime系列(引文),可能会在其中发现一个词:类对象
。那么什么是类对象
?
先看一段代码
NSArray *arr = [NSArray array];
他是怎么运行的?
上篇文章中提到,[receiver message]
底层会调用id objc_msgSend(id self, SEL op, ...)
。再来回顾一下id
是什么
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
id指向一个对象,可以猜测[NSArray array]
中的NSArray
也是一个对象
。可NSArray怎么会是对象?这就要引出本文的另一个主角元类
了。
元类
其实NSArray和arr一样,也是对象
,叫做类对象
。
可以看到,Class
中也有个isa
指针,他的指向就是自身的元类。
元类是类对象的类,类对象是元类的实例。
基于这种设计模式,不难发现:
1.我们以前调用 "+" 开头的类方法实际是在调用元类的对象方法
2.由于每个类有且只有一个,所以每个类对象都是其对应元类的单例
那么,元类是对象吗?
答案是肯定的,元类是对象。
如果元类也是对象,元类的类又是什么?
元类的类
再来看一张网上的示意图
示意图.png- 图解
我们接触到的大部分OC对象都继承自NSObject,这里直接以NSObject为例。
1.每个实例对象的类都是类对象,每个类对象的类都是元类对象,每个元类对象的类都是根元类(root meta class的isa指向自身)
2.类对象的父类最终继承自根类对象NSObject,NSObject的父类为nil
3.元类对象(包括根元类)的父类最终继承自根类对象NSObject
可见,类与元类是一个闭环。
网友评论
第二,那我在NSArray.h里面的+ (instancetype)array;方法明明有声明啊。。
作者能不能屈尊来解答一下。。
>>isa是受保护的,无法直接访问
>>在类对象中调用`+ (Class)class`返回仍然是本身,底层调用`objc_getClass`,`objc_getMetaClass`同样返回类对象本身
比较地址的代码可以这样写
```
NSArray *arr = [NSArray array];
Class cls = [arr class];
int i = 0;
while (1) {
NSLog(@"%d---cls:%p---nsobject:%p", i, cls, objc_getMetaClass("NSObject"));
i++;
if (cls == objc_getMetaClass("NSObject")) break;
cls = object_getClass(cls);
}
```