《Objective-C runtime系列 1》消息发送及转发机制
Objective-C是基于C,加入了面向对象面向对象特性和消息转发机制的动态语言,Runtime系统来动态创建类和对象进行消息发送和转发。
一,ObjC的消息发送机制
在ObjC中用某对象调用方法时 [receiver message],会被runtime转换成
id objc_msgSend ( id self, SEL op, ... );
下面用代码形式说明一下消息发送机制。向Test实例发送print消息
我们用clang编辑器的命令clang -rewrite-objc main.m,把下边代码转换成.cpp文件,转化后在文件夹下生成了一个大约十万行代码的main.cpp文件。翻到最下边,找到我们要找的main函数中的代码。 如图
由上图代码可以看出,[test print]代码被转化成了
((void (*)(id, SEL))(void *)objc_msgSend)((id)test, sel_registerName("print"));
其中(id)test代表我们的test对象。 sel_registerName("print")则代表了SEL方法选择器。
1.1 Runtime数据结构
如图,id是一个通用类型的指针,指向任何OC对象,能表示任何对象,
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
其实id就是指向objc_object结构体类型的指针,它包含一个class isa变量。 根据isa可以顺藤摸瓜找到对应的类。
typedef struct objc_selector *SEL;
其实它就是映射到方法的C字符串,你可以通过ObjC编译器命令@selector()或者Runtime系统的sel_registerName函数来获取一个SEL类型的方法选择器。
如果你知道selector对应的方法名是什么,可以通过NSString* NSStringFromSelector(SEL aSelector)方法将SEL转化为字符串,再用NSLog打印。
Class
isa指针的类型是Class,Class表示所属对象的类。
typedef struct objc_class *Class;
可以看出,Class其实是指向objc_class结构体的指针。在runtime.h文件中我们找到objc_class的定义,如下图
isa表示Class对象的Class,也就是Meta Class(元类)。
objc_ivar_list是属性列表,其实是一个链表,存储着多个objc_ivar.
ojcg_method_list是方法列表, 也会一个链表,存放着多个objc_method;
objc_cache用来缓存经常用到的方法。
objc_protocol_lists表示类遵从哪些协议。
1.2 objc_msgSend函数
根据receiver对象的isa指针获取它对应的class;
优先在class的cache查找message方法,如果找不到,到methodlists中查找。
如果没有找到,再到super_class查找。
一旦找到message方法,就执行它的实现IMP。
一直找不到时,就会进入消息转发机制。 下篇继续~