iOS 的实例对象、类、元类

1,089 阅读4分钟

类、元类的定义

类:类(英语:class)在面向对象编程中是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法。

元类:在面向对象程序设计中,元类(英语:metaclass)是一种实例是类的类。普通的类定义的是特定对象的行为,元类定义的则是特定的类及其对象的行为。 类是实例对象的描述,元类是类对象的描述。
举个例子 NSObject *obj = [NSObject new];
NSObject 是 实例对象 obj 的描述,NSObject 的元类是 NSObject 类对象的描述。

实例对象、类、元类之间的关系

我们看一下实例对象、类、元类之间的关系图。

2628633-b0920175e2a327c7.webp

一、实例对象、类对象、元类的 isa 指向及父类指向说明

下边笔者说明下上图中 isa 和父类指向。

  1. 实例对象的 isa 指针指向类对象;
  2. 类对象的 isa 指针指向元类对象;
  3. 元类对象的 isa 指针指向根元类(NSObject元类);
  4. 根元类(NSObject元类)的 isa 指针指向自己;
  1. 子类的元类的父类指向父类的元类;
  2. NSObject的父类为nil;
  3. 根元类(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元类)的父类地址:0x7fff86cb8660NSObject类地址:0x7fff86cb8660

相关文章