类、元类的定义
类:类(英语:class)在面向对象编程中是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法。
元类:在面向对象程序设计中,元类(英语:metaclass)是一种实例是类的类。普通的类定义的是特定对象的行为,元类定义的则是特定的类及其对象的行为。 类是实例对象的描述,元类是类对象的描述。
举个例子NSObject *obj = [NSObject new];
NSObject 是 实例对象 obj 的描述,NSObject 的元类是 NSObject 类对象的描述。
实例对象、类、元类之间的关系
我们看一下实例对象、类、元类之间的关系图。
一、实例对象、类对象、元类的 isa 指向及父类指向说明
下边笔者说明下上图中 isa 和父类指向。
- 实例对象的 isa 指针指向类对象;
- 类对象的 isa 指针指向元类对象;
- 元类对象的 isa 指针指向根元类(NSObject元类);
- 根元类(NSObject元类)的 isa 指针指向自己;
- 子类的元类的父类指向父类的元类;
- NSObject的父类为nil;
- 根元类(NSObject元类)的父类指向NSObject。
0. 下文会用到的函数说明
// 注:使用如下函数需要在自己的文件中引入runtime头文件 即 #import <objc/runtime.h>
// 如果obj为实例对象返回obj对应的类对象,如果obj为类对象返回obj对应的元类对象,如果obj为元类对象,返回obj的元类对象。
OBJC_EXPORT Class _Nullable object_getClass(id _Nullable obj) ;
// 返回指定类名name的元类
OBJC_EXPORT Class _Nullable objc_getMetaClass(const char * _Nonnull name);
// 查看指定类是否为元类
OBJC_EXPORT BOOL class_isMetaClass(Class _Nullable cls);
// 返回指定类的父类
OBJC_EXPORT Class _Nullable class_getSuperclass(Class _Nullable cls) ;
我们可以使用代码验证一下实例对象、类、元类关系图的正确性。 为了验证对象、类对象、元类的isa指向及父类指向,笔者创建了 2 个类,分别是 QiSuperClass、QiSubClass。 QiSuperClass 继承自 NSObject,QiSubClass 继承自 QiSuperClass。
笔者写了如下示例代码做验证。
//! 验证实例对象、类对象、元类对象的isa及父类指向
- (void)instanceClassMetaClassISASuperClicked {
QiSubClass *subClassInstance = [QiSubClass new];
// 类对象
Class subClass = object_getClass(subClassInstance);
// 元类对象
Class subMetaClass = object_getClass(subClass);
// 元类对象的元类对象
Class subMetaClassMetaClass = object_getClass(subMetaClass);
// 1. 实例对象的 isa 指针指向类对象
QiLog(@"----1. 实例对象的 isa 指针指向类对象----");
QiLog(@"QiSubClass的类对象地址:%p,QiSubClass类对象地址:%p", subClass, [QiSubClass class]);
// 2. 类对象的 isa 指针指向元类对象;
QiLog(@"----2. 类对象的 isa 指针指向元类对象;----");
QiLog(@"QiSubClass元类对象地址:%p,QiSubClass元类对象地址:%p", subMetaClass, objc_getMetaClass("QiSubClass"));
// 3. 元类对象的 isa 指针指向根元类(NSObject元类);
QiLog(@"----3. 元类对象的 isa 指针指向根元类(NSObject元类)----");
QiLog(@"QiSubClass元类对象的元类对象地址:%p,根元类(NSObject元类)的对象地址:%p", subMetaClassMetaClass, objc_getMetaClass("NSObject"));
// 4. 根元类(NSObject元类)的 isa 指针指向自己;
QiLog(@"----4. 根元类(NSObject元类)的 isa 指针指向自己----");
QiLog(@"根元类(NSObject元类)的对象地址:%p,根元类(NSObject元类)的对象的isa指针地址:%p", objc_getMetaClass("NSObject"), object_getClass(objc_getMetaClass("NSObject")));
// 1. 子类的元类的父类指向父类的元类;
QiLog(@"----1. 子类的元类的父类指向父类的元类----");
QiLog(@"QiSubClass的元类的父类对象地址:%p,QiSuperClass的元类地址:%p", class_getSuperclass(objc_getMetaClass("QiSubClass")), objc_getMetaClass("QiSuperClass"));
// 2. NSObject的父类为nil;
QiLog(@"----2. NSObject的父类为nil----");
QiLog(@"NSObject的父类对象:%@", class_getSuperclass([NSObject class]));
// 3. 根元类(NSObject元类)的父类指向NSObject。
QiLog(@"----3. 根元类(NSObject元类)的父类指向NSObject----");
QiLog(@"根元类(NSObject元类)的父类地址:%p,NSObject类地址:%p", class_getSuperclass(objc_getMetaClass("NSObject")), [NSObject class]);
}
笔者整理后的输出结果如下:
----1. 实例对象的 isa 指针指向类对象----
QiSubClass的类对象地址:0x10dad86c0,QiSubClass类对象地址:0x10dad86c0
----2. 类对象的 isa 指针指向元类对象;----
QiSubClass元类对象地址:0x10dad8698,QiSubClass元类对象地址:0x10dad8698
----3. 元类对象的 isa 指针指向根元类(NSObject元类)----
QiSubClass元类对象的元类对象地址:0x7fff86cb8638,根元类(NSObject元类)的对象地址:0x7fff86cb8638
----4. 根元类(NSObject元类)的 isa 指针指向自己----
根元类(NSObject元类)的对象地址:0x7fff86cb8638,根元类(NSObject元类)的对象的isa指针地址:0x7fff86cb8638
----1. 子类的元类的父类指向父类的元类----
QiSubClass的元类的父类对象地址:0x10dad8508,QiSuperClass的元类地址:0x10dad8508
----2. NSObject的父类为nil----
NSObject的父类对象:(null)
----3. 根元类(NSObject元类)的父类指向NSObject----
根元类(NSObject元类)的父类地址:0x7fff86cb8660,NSObject类地址:0x7fff86cb8660