OC对象的本质之:对象的类型

201 阅读3分钟

我们以往讨论的OC对象,一般是指alloc出来的对象,其实Objective-C中的对象主要分为3种:instance对象(实例对象)、class对象(类对象)、meta-class对象(元类对象),而alloc出来的对象则叫做instance对象(实例对象)。

NSObject *obj = [[NSObject alloc] init];

这里的obj就是实例对象。

instance对象(实例对象)

instance对象(实例对象)就是通过类alloc出来的对象,每次调用alloc都会产生新的实例对象。

NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];

如上,obj1obj2都是NSObject的instance对象(实例对象)。它们是不同的两个对象,分别占据着两块不同的内存。

我们在之前分享的OC的内存对齐中已经知道,实例对象的内存大小是根据其成员变量的大小计算一个size,再根据OC自己内存对齐来决定所分配的内存大小,那么我们大概可以知道:实例对象在内存中存储的信息其实就是成员变量(包括isa)。

那方法存在哪里呢? 在类对象里。

class对象(类对象)

类对象是Class类型的对象,Class其实是一个指针,它指向这个类对象的内存地址。

typedef struct objc_class *Class;

一个class对象(类对象)在内存中的地址是唯一的,每个类在内存中有且只有一个类对象。

NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
Class objClass3 = object_getClass(obj1);
Class objClass4 = object_getClass(obj2);
Class objClass5 = [NSObject class];
NSLog(@"\nobjClass1:%p\nobjClass2:%p\nobjClass3:%p\nobjClass4:%p\nobjClass5:%p", objClass1, objClass2, objClass3, objClass4, objClass5);
输出:
objClass1:0x7ff84ced9ab0
objClass2:0x7ff84ced9ab0
objClass3:0x7ff84ced9ab0
objClass4:0x7ff84ced9ab0
objClass5:0x7ff84ced9ab0

class对象(类对象)在内存中存储的信息主要有:

  • isa指针
  • superclass指针
  • 类的属性信息(@property)
  • 类的对象方法信息(instance method)
  • 类的协议信息(protocol)
  • 类的成员变量信息(ivar)
  • ...

meta-class对象(元类对象)

实例对象是类对象的实例,我们也可以把类对象看做是元类对象的一个实例,元类对象也是Class类型。

// 实例对象
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
NSLog(@"\nobobj1:%p\nobj2:%p", obj1, obj2);

// 类对象
Class objClass1 = [obj1 class];
Class objClass2 = [obj2 class];
Class objClass3 = object_getClass(obj1);
Class objClass4 = object_getClass(obj2);
Class objClass5 = [NSObject class];
NSLog(@"\nobjClass1:%p\nobjClass2:%p\nobjClass3:%p\nobjClass4:%p\nobjClass5:%p", objClass1, objClass2, objClass3, objClass4, objClass5);

//元类对象:通过参数传入类对象获得
Class objMetaClass1 = object_getClass([objClass1 class]);
Class objMetaClass2 = object_getClass([NSObject class]);
NSLog(@"\nobjMetaClass1:%p\nobjMetaClass2:%p", objMetaClass1, objMetaClass2);

输出:
obj1:0x60000000c030
obj2:0x60000000c040

objClass1:0x7ff84ced9ab0
objClass2:0x7ff84ced9ab0
objClass3:0x7ff84ced9ab0
objClass4:0x7ff84ced9ab0
objClass5:0x7ff84ced9ab0

objMetaClass1:0x7ff84ced9a60
objMetaClass2:0x7ff84ced9a60

需要注意的是,class方法获取到的就是类对象,并不能通过类对象调用class方法获取元类对象,以下代码获取的都是类对象:

Class objClass1 = [[NSObject class] class];
Class objClass2 = [NSObject class];
NSLog(@"\nobjClass1:%p\nobjClass2:%p", objClass1, objClass2);
输出:
objClass1:0x7ff84ced9ab0
objClass2:0x7ff84ced9ab0

我们可以通过class_isMetaClass(Class  _Nullable __unsafe_unretained cls)来判断一个对象是不是元类对象:

Class objClass = [NSObject class];
Class objMetaClass = object_getClass([NSObject class]);
NSLog(@"\nobjClass isMetaClass:%d\nobjMetaClass isMetaClass:%d", class_isMetaClass(objClass), class_isMetaClass(objMetaClass));
输出:
objClass isMetaClass:0
objMetaClass isMetaClass:1

元类对象和类对象的内存结构是一样的,只是用途不一样。 meta-class对象(元类对象)在内存中存储的信息主要有:

  • isa指针
  • superclass指针
  • 类的类方法信息(class method)
  • ...