在Objective-C中,消息直到运行时才绑定到方法实现上。下面来看看消息发送具体是怎么样的。
新建一个helloClass类在 helloClass 类里面定义一个实例方法和一个类方法:
新建一个 HelloWorldClass 的类,继承自 HelloClass 类,在里面写一个helloWorldMethod方法:
通过clang命令:
$ clang -rewrite-legacy-objc HelloWorldClass.m
得到 helloWorldMethod方法C++代码:
首先,我们看下 helloWorldMethod 方法C++代码中两个参数,这两个参数在OC方法中是隐藏的,第一个参数是调用该方法的对象,第二个参数就是该方法的SEL。
在运行时,消息绑定到方法实现上,编译器将方法调用转换为objc_msgSend,参考向实例对象发送 helloInstanceMethod 消息:
objc_msgSend(obj, sel_registerName("helloInstanceMethod"))
当我们obj对象初始化的时候,也就是初始化了obj 结构体 objc_class。
当我们向obj对象发送helloInstanceMethod消息时,objc_msgSend函数通过obj对象中的isa指针获取到类的结构体,先从方法缓存方法列表cache methodLists中寻找,找到了调用对应函数实现;如果没有找到,再从方法列表methodLists里面找,如果找不到,一直沿着继承树往基类找;基类中如果没有就会走消息转发、动态方法解析(后面会讲)。
前面说过类也是对象,向类对象发送消息的流程和向实例对象发送消息的流程是一样的,这里不细说。
当我们向父类发送消息时,参考向super发送 helloInstanceMethod 消息,使用的是objc_msgSendSuper函数:
objc_msgSendSuper(struct objc_super *super, SEL op, ...)
它的第一个参数是一个指向objc_super 结构体的指针,objc_super结构体在objc/message.h中的定义如下:
/// Specifies the superclass of an instance.
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained id receiver;
/// Specifies the particular superclass of the instance to message.
#if !defined(__cplusplus) && !__OBJC2__
/* For compatibility with old objc-runtime.h header */
__unsafe_unretained Class class;
#else
__unsafe_unretained Class super_class;
#endif
/* super_class is the first class to search */
};
#endif
一共有二个参数,第一个是消息接受的实例,第二个是父类。helloInstanceMethod中的objc_super结构第一个参数传入的self,第二个参数最后得到父类HelloClass。使用super编译器标示符发送消息实际上和self发送消息的机制是一样的,只是去父类的方法列表中找该方法。
最后使用clang命令
$ clang -rewrite-objc HelloWorldClass.m
发现一些关于元类的细节:
前面说的元类的东西一直没有看到,在这个里面证明了”OC-类和对象”里面的那张isa游走图。
根据这张图可以推断出来HelloWorldClass类的isa指针指向HelloWorldClass的元类,而HelloWorldClass的元类的isa指针执行的是基类NSObject的元类。