简单来说,Objective-C runtime是一个实现Objective-C语言的C库。对象可以用C语言中的结构体表示,而方法(methods)可以用C函数实现。事实上,他们 差不多也是这么干了,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,Objective-C程序员可以在程序运行时创建,检 查,修改类,对象和它们的方法。例如一个普通类,我们写好之后,Runtime会进行处理。最后变成以下结构:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;//父类
const char *name OBJC2_UNAVAILABLE;//类名
long version OBJC2_UNAVAILABLE;//设备名
long info OBJC2_UNAVAILABLE;//设备信息
long instance_size OBJC2_UNAVAILABLE;//空间大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;//类中参数数组
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;//类中函数数组
struct objc_cache *cache OBJC2_UNAVAILABLE; //近期使用过的方法,放入这里。快速查找
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;//协议数组
#endif
} OBJC2_UNAVAILABLE;
通过一个结构体的方式,来存放类中的信息。
再比如,我们调用的实例方法。从本质上来看是用C语言中的函数来实现的,但是在外面我们还是对实例方法使用结构体进行了封装。结构体如下:
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;//函数名
char *method_types OBJC2_UNAVAILABLE;//method_types是个char指针,存储着方法的参数类型和返回值类型。
IMP method_imp OBJC2_UNAVAILABLE;//函数指针,指向这个函数的首地址
}
在重复一下,Objective-C runtime是一个实现Objective-C语言的C库。
在oc中有一个id的概念。他的定义为:
typedef struct objc_object *id;
struct objc_object {
Class isa;
};
Objective-C中的object在最后会被转换成C的结构体,而在这个struct中有一个 isa 指针,指向它的类别 Class。
typedef struct objc_class *Class;
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
上面是类在runtime中的源代码,从这看,类其实也是一个结构体。这个结构体中的isa指向一个Metaclass。
仔细一看,发现 Class isa,原来,isa(Metaclass)的源码还是类的源码:
typedef struct objc_class *Class;
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
Class存放类信息,方法数组存放实例方法;Meta Class存放类信息,方法数组存放类方法。
每一个object都有一个isa指针,isa指针指向自己的Class 每个Class都有一个isa指针指向一个唯一的Meta Class
typedef struct objc_selector *SEL;
SEL是一个指向objc_selector结构体的指针。而 objc_selector 的定义并没有在runtime.h中给出定义。
编译器会根据每个方法的方法名为那个方法生成唯一的SEL。只要方法名相同,那么它的SEL就是一样的。每一个方法都对应着一个SEL。
typedef id (*IMP)(id, SEL, …);
IMP本质就是一个函数指针,这个被指向的函数包含一个接收消息的对象id,调用方法的SEL,以及一些方法参数,并返回一个id。因此我们可以通过SEL获得它所对应的IMP,在取得了函数指针之后,也就意味着我们取得了需要执行方法的代码入口,这样我们就可以像普通的C语言函数调用一样使用这个函数指针。
typedef struct objc_method *Method;
struct objc_method { SEL method_name OBJC2_UNAVAILABLE; char *method_types OBJC2_UNAVAILABLE; IMP method_imp OBJC2_UNAVAILABLE; } OBJC2_UNAVAILABLE;
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE; OBJC2_UNAVAILABLE;
在创建一个类的时候,我们将类中的实例方法存放到objc_class结构体(类的结构体,前面提到)中的objc_method_list **methodLists中。将类中的类方法存放到相应的MetaClass中的类结构中的objc_method_list **methodLists中。我们可以理解为objc_class中 method list保存了一组SEL<->IMP的映射。
在Objective-C中,消息直到运行时才会绑定到方法的实现上。编译器会把代码中[target doSth]转换成 objc_msgSend消息函数,这个函数完成了动态绑定的所有事情。它的运行流程如下:
寻找IMP的过程:
看Category的源码,不用想就知道这个又是一个结构体
typedef struct objc_category *Category;
struct objc_category {
char *category_name OBJC2_UNAVAILABLE;//分类名
char *class_name OBJC2_UNAVAILABLE;//类名
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE;//实例方法列表
struct objc_method_list *class_methods OBJC2_UNAVAILABLE;//类方法列表
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;//协议列表
}
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
这里我们注意第三个成员 ivar_offset。它表示基地址偏移字节。我们通过字节偏移量来获取变量的地址。(具体方式不展开)
存放在之前我们仿佛强调的objc_class中的struct objc_ivar_list *ivars中 。
类中的Property属性被编译器转换成了Ivar,并且自动添加了我们熟悉的Set和Get方法。
http://www.cocoachina.com/ios/20141224/10740.html
刨根问底Objective-C Runtime(1)- Self & Super
刨根问底Objective-C Runtime(2)- Object & Class & Meta Class
刨根问底Objective-C Runtime(3)- 消息和Category
刨根问底Objective-C Runtime(4)- 成员变量与属性
Objective-C Runtime 运行时之一:类与对象
Objective-C Runtime 运行时之二:成员变量与属性
Objective-C Runtime 运行时之三:方法与消息
Objective-C Runtime 运行时之四:Method Swizzling
Objective-C Runtime 运行时之五:协议与分类
Objective-C Runtime 运行时之六:拾遗