一、OC对象分为三类
1、实例对象 :instance对象
2、类对象: class对象
3、元类对象 :meta-class对象
二、OC对象内存分配
1、实例对象:alloc出来的对象,分布在堆区。
2、类对象:系统编译加载进内存时自动创建的,在内存中只存在一份,分布在数据区。
3、元类对象:系统编译加载进内存时自动创建的,在内存中只存在一份,分布在数据区。
从下面图打印的地址可以看出,类对象及元类对象的地址与age全局变量地址相近说明都是存在数据区。实例对象地址相比数据段地址更大,栈地址是最大部分的地址,与内存的区域分配原则相同。可确定实例对象内存是属于堆区,栈变量内存地址是栈区(高地址)。
总结:每个类有且只有一个类对象、元类对象,存储在数据区。
三、struct objc_class的结构
1、类对象的结构(非objc2情况下)在目前的objc2后是不可用的,过时的。
从objc源码中查找https://opensource.apple.com/tarballs/objc4/
在目前的objc2.0的最新源码中,struce objc_class结构如下:
总结下struct objc_class的结构简化表示如下:
注意:Class是struct objc_class结构指针,
总结Class里面成员包括如下:
class对象在内存中存储的信息主要包括: isa指针、superClass指针、类的属性信息(properties)、类的对象实例方法列表(methods)、协议列表(protocols)、成员变量列表(ivars)、方法缓存列表(cache)。
获取类对象的方法如下:
注意点:Class objClass = [[NSObject class]class];这样得到的都是类对象,不是元类对象。
2、元类meta-class的结构与类对象class的结构是一样的。(每个类都存在唯一的一个元类对象meta-class)
元类对象meta-class的用途,内存存储的主要信息:存储着类方法列表,缓存列表,isa,superClass等信息。
获取元类API: Class metaclass = object_getClass([NSObject class]);
四、isa指针与superclass总结
1、instance的isa指向class。
2、class的isa指向meta-class。
3、meta-class的isa指向基类的meta-class。
4、class的superclass指向父类的class,如果没有父类,superclass指针为nil。
5、meta-class的superclass指向父类的meta-class,基类的meta-class的superclass指向基类的class(特殊点)。
6、instance调用对象方法的轨迹:isa找到class,先从缓存列表找然后去方法列表找,如果方法不存在,就通过superclass找父类。
7、class调用类方法的轨迹:isa找meta-class,先从缓存列表找然后去方法列表找,如果方法不存在,就通过superclass找父类。
四、isa指针的真实地址
1、实例对象的isa指针是指向类对象的地址值。类对象的isa指针指向的是元类对象的地址值。但是是否是这样呢?请看截图:
从打印的结果可以看出,person对象实例的isa的值:0x001d800100002531 与person的类对象的地址值:0x0000000100002530是不同的。然而isa&0x00007ffffffffff8位运算后,可以得到person类对象的地址值。
原因:在arm64之前,isa的值就是类对象or元类对象的地址值,但是在arm64架构之后,程序设计有所改变,isa的值需要进行一次位运算(需要&ISA_MASK一个掩码)后,才能够得到isa的真实地址值。
注意:可以在https://opensource.apple.com/tarballs/objc4/源码里面找到ISA_MASK.