平时也有了解一些 Runtime 相关的知识,但都是只处于知道阶段没有详细了解过,最近没有那么忙了准备抽个时间来边学边记录一下
初识
Runtime 字面意思运行时,是一个将 C 语言转化为面向对象语言的扩展,是 Objective-C 被称之为动态语言的核心。
在 C 语言中函数的调用在编译期就已经确定,而在 Objective-C 中在编译期内无法确定具体调用哪个函数,只有在真正运行的时候才确定调用。
本篇博客具体记录基于 objc2.0 对象在 Runtime 中的定义。
objc_class
objc2.0 之后的 objc_class 定义如下
typedef struct objc_class *Class;
typedef struct objc_object *id;
struct objc_object {
private:
isa_t isa;
}
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
}
从以上代码可以得出:
- Objective-C 的对象都是 C 语言结构体
id
是指向struct objc_object
的一个指针class
是指向objc_class
的指针objc_class
继承于objc_object
isa & superclass
isa 是一个 isa_t
的结构体,它包含了当前对象指向的类的信息。
- 对象中的 isa 指向它的类对象
- 类对象中的 isa 指向它的元类对象
superclass 指向它的父类对象。
对应关系图如下:
类对象的 isa 指向一个 meta class
元类,所有元类的 isa 都指向了 Root class (meta)
,而 Root class (meta)
是 Root class (class)
的子类,即 NSObject / NSProxy 的子类。
cache
cache 用于方法性能优化,每次发送消息时,优先在 cache 中查找,查找不到的情况下去类和它的父类方法列表中查找,找不到的情况下消息转发,找到之后会将方法缓存在 cache 中。
找到 cache_t 结构体的具体实现:
struct cache_t {
struct bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
}
typedef unsigned int uint32_t;
typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits
typedef unsigned long uintptr_t;
typedef uintptr_t cache_key_t;
struct bucket_t {
private:
cache_key_t _key;
IMP _imp;
}
- _buckets 是一个散列表,用来做方法缓存
- _mask 分配可以缓存的
bucket_t
总数 - _occupied 实际占用缓存的
bucket_t
个数
bits
class_data_bits_t
源码实现如下
struct class_data_bits_t {
// Values are the FAST_ flags above.
uintptr_t bits;
}
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;
}
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
中存放类的属性列表、方法列表、遵循的协议列表、只读的 class_ro_t
等,它提供了运行时对类进行扩展的能力。
class_ro_t
存储的信息基本都是编译时就已经可以确定的信息,在编译之后不做修改。
类初始化之前 objc_class->data()
返回的指针指向的是一个 class_ro_t
结构体,初始化时类调用 realizeClass
静态方法,开辟一个 class_rw_t
的空间,并把 class_ro_t
指针赋值给 class_rw_t->ro
,具体实现细节有时间在仔细研究研究。。