在CH1-Q1和CH1-Q2两个小节中,我们学习了OC实例对象的本质,并且能够掌握OC实例对象在内存是如何分配的,一个NSObject对象占用多少内存空间、一个自定义的实例对象占用多少内存空间、内存对齐等知识点。那么我们是否注意到,上一章两个小节的表述都是在描述
实例对象
这一种OC对象的,那么Objective-C是否存在其他类型的对象呢?
其实OC对象可以分为三种:
①实例对象(instance)
②类对象(class)
③元类对象(meta-class)
instance(实例对象)
instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象。因为每次调用alloc都会开辟新的内存空间,给予存储新的实例对象所使用,因此每一个实例对象的内存地址都是不一样的。
上面的obj1和obj2就是NSObject的instance对象,他们是不同的两个对象,分别占用了不同的内存空间。
instance对象在内存中存储信息包括:
①isa指针
②其他成员变量
那么我们可能在这里有一个疑问,我们的类并不单单有成员变量、还有方法、协议等信息,那么这些信息是存放在内存的哪里呢?我们不难想到,类的方法、协议这些信息通常是这个类的所有实例对象都拥有的信息,所以我们没有必要像成员变量那样,每一个实例对象都存放一份方法列表、协议等信息,因为这样会浪费很多的空间,其实我们只需要在内存中存放一份关于类的方法、协议等信息即可。那么我们就要提及到类对象
和元类对象
了。
class (类对象)
一个类的类对象在内存中有且只有只有一份,它们指向的内存空间都是同一个地址。
我们可以通过以下的几种方式获取类对象:
①通过实例对象的class方法获取得到类对象。
NSObject *obj1 = [[NSObject alloc] init];
Class objClass1 = [obj1 class];
②直接通过类的类方法class获取得到类对象:
Class objClass1 = [NSObject class];
③通过<objc/runtime.h>
获取类对象:
Class objClass1 = object_getClass(object1);
我们可以打印一下以上几个类对象的地址:
通过上面的打印我们能够确定一个类的类对象在内存中有且只有只有一份,它们指向的内存空间都是同一个地址。那么类对象在内存中的作用是什么呢?
类对象在内存中存储信息包括:
①isa指针
②superclass指针
③类的属性信息(@property)、类的对象方法信息(instance method)
④类的协议信息(protocol)、类的成员变量信息(ivar)
isa、superclass、类的属性信息(@property)、类的成员变量信息(ivar)(不是成员变量的值,只是成员变量的名字、类型、描述信息)、类的对象方法信息(instance method,-号开头的方法)、类的协议信息(protocol)
其中类的成员变量信息跟instance对象中提及到的成员变量是有区别的,instance对象存储的是成员变量的值,而类对象存储的是该成员变量的类型、名字,例如一个Person类有一个成员变量height,它的类型是double,那么类对象存储的就是它的类型和这个变量的名字,而实例对象存储的是height这个成员变量的值。
我们还可以发现类对象存储的只有类的对象方法信息,那么我们一个类可能有类方法(+),这种类方法就是存储在接下来提到的元类对象中。
meta-class (元类对象)
一个类的元类对象也跟其类对象相似,在内存中有且只有只有一份。
通过<objc/runtime.h>
的object_getClass
方法我们能够获取一个类的类对象:
Class metaClass = object_getClass([NSObject class]);
注意1:这里传入参数是类对象,而上面获取一个类的类对象时,我们传入的是实例对象。
注意2:元类对象和类对象的底层结构是一样的,因为他们都是Class这个结构体组成的。
元类对象在在内存中存储信息包括:
①isa指针
②superclass指针
③类的类方法信息
下一节我们会继续介绍每一种对象里面的isa、superclass、类的各种信息的作用,以及它们的之间有什么联系。