和对象(objc_object
结构体)一样,类(objc_class
结构体)在新的运行时中也有了很大的改变,在 objc-runtime-new.h
中可以找到它的定义
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
// 省略掉一些结构体方法
};
可以注意到,换上 C++ 之后,objc_class
结构体直接从 objc_object
结构体继承下来了,并且注释了 isa
的存在。 比较之前的定义,第二个成员依旧是指向父类的指针,但是之后就完全不一样了,可以看到 cache
的类型变成了 cache_t
,其余的信息都塞进了 bits
里。
bits
的右边可以看到好心的开发者留给后人的注释,解释了这个成员也是类似于 isa
一样,将位(bit)用作不同用途。其中最重要的就是 class_rw_t *
了,可以看到 data()
函数就是用来返回这个结构体指针的,class_rw_t
的名字表示它是类的可读可写数据。
继续在 objc-runtime-new.h
中看到 class_rw_t
结构体的定义
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
}
可以注意到它有一个 ro
成员,是类的只读数据,这是类在编译时就确定了的东西,它的定义如下
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
在实现中,class_rw_t
结构体的 methods
、properties
和 protocols
会包含它的 ro
中对应的数据和 category 的数据,这是类在加载到运行时时做的事情,之后的文章会有详细的说明。这样,在消息发送中查找方法时,是不需要在 ro
中搜索的。
总结
大致了解了一下类在 Objective-C 运行时中的实现,具体的细节部分也还需要分析不同功能时具体分析了。