那么一个Objective-C类、对象是如何通过C/C++实现、储存的呢?
objc4
源码获取一些信息
objc4 的源码不能直接编译,需要配置相关环境才能运行。可以在这里下载可调式的源码。
objc 运行时源码的入口在 void _objc_init(void) 函数。
objc-private.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14
struct objc_object { private: //isa是一个union联合体,包含这个对象所属类的信息 isa_t isa; public: // ISA() assumes this is NOT a tagged pointer object Class ISA(); // getIsa() allows this to be a tagged pointer object Class getIsa(); ... }
objc-runtime-new.h
1 2 3 4 5 6 7 8 9 10 11 12 13
struct objc_class : objc_object { // Class ISA; (ISA继承于objc_object) Class superclass; //当前类父类 cache_t cache; // formerly cache pointer and vtable 缓存指针和vtable,提高方法调用效率 class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags 存储类的方法、属性、协议等信息 // 针对 class_data_bits_t 的 data() 函数的封装,最终返回一个 class_rw_t 类型的结构体变量 // Objective-C 类中的属性、方法还有遵循的协议等信息都保存在 class_rw_t 中 class_rw_t *data () { return bits.data(); } ... }
通过源码可以得知,objc_class继承于objc_object,所以二者都存在isa成员变量,类型为:isa_t。isa_t是一个union。
我们回到objc-private.h中
1 2 3 4 5 6 7 8 9 10 11 12
union isa_t { isa_t () { } isa_t(uintptr_t value) : bits(value) { } //所属类 Class cls; uintptr_t bits; struct { ISA_BITFIELD; // defined in isa.h }; };
isa_t包含一个成员变量 cls。
每个objc_object通过自己持有的isa查找到自己所属的类。而对于objc_class来说,可以通过isa找到自己的mate class,即元类。
对于IAS_BITFIELD,定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
//__arm64__ uintptr_t nonpointer : 1; \ uintptr_t has_assoc : 1; \ uintptr_t has_cxx_dtor : 1; \ uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \ uintptr_t magic : 6; \ uintptr_t weakly_referenced : 1; \ uintptr_t deallocating : 1; \ uintptr_t has_sidetable_rc : 1; \ uintptr_t extra_rc : 19
nonpointer
表示 isa_t 的类型,0 表示 raw isa,也就是没有结构体的部分,访问对象的 isa 会直接返回一个指向 cls 的指针,也就是在 iPhone 迁移到 64 位系统之前时 isa 的类型。1 表示当前 isa 不是指针,但是其中也有 cls 的信息,只是其中关于类的指针都是保存在 shiftcls 中。
has_assoc
对象含有或者曾经含有关联引用(category相关),没有关联引用的可以更快地释放内存(object dealloc相关,其他文章会说到)。
has_cxx_dtor
表示当前对象有 C++ 或者 ObjC 的析构器(destructor),如果没有析构器就会快速释放内存(object dealloc相关)。
shiftcls
见nonpointer
magic
用于调试器判断当前对象是真的对象还是没有初始化的空间
weakly_referenced
对象被指向或者曾经指向一个 ARC 的弱变量,没有弱引用的对象可以更快释放
deallocating
对象正在释放内存
has_sidetable_rc
对象的引用计数太大了,存不下
extra_rc
对象的引用计数超过 1,会存在这个这个里面,如果引用计数为 10,extra_rc 的值就为 9。