消息发送(Messaging)是 Runtime 通过 selector 快速查找 IMP 的过程,有了函数指针就可以执行对应的方法实现;
消息转发(Message Forwarding)是在查找 IMP 失败后执行一系列转发流程的慢速通道,如果不作转发处理,则会打日志和抛出异常
函数
函数的四要素
- 名称 SEL name
- 返回值 const char* types
- 参数 const char* types
- 函数体 IMP
SEL
SEL是selector在Objc中的表示类型,selector是方法选择器,可以理解为区分方法的 ID,而这个 ID 的数据结构是SEL:
typedef struct objc_selector *SEL;
IMP
IMP在objc.h中的定义是:
typedef void (*IMP)(void /* id, SEL, ... */ );
它就是一个函数指针,这是由编译器生成的。当你发起一个 ObjC 消息之后,最终它会执行的那段代码,就是由这个函数指针指定的。而 IMP 这个函数指针就指向了这个方法的实现。
objc_msgSend
伪代码如下或类似的逻辑,反正就是获取 IMP 并调用
1 | id objc_msgSend(id self, SEL _cmd, ...) { |
self 和 super
看一个问题
1 | @interface Phone:Mobile |
结果是都打印出来 Phone。
来看一下[self class],[super class]的消息传递
这里可以看到 objc_super 结构体当中 receiver 就是当前对象 。 也就是说 无论是 [self class]或者 [super class] ,接收者都是当前对象!
解析
当前的实例是 phone
[self class] –>objc_msgSend(self,@selector(class)), 首先通过实例的 isa 指针找到 phone 的类对象,它本身是没有 class 方法的,然后往父类找,也没有。 顺次一直查找到根类也就是 NSObject ,将 class的具体实现返回给调用方,也就是 phone
1 | instance of Subclass --> Subclass(class) -->Superclass(class)-->Root class(class) |
[super class] –>objc_msgSendSuper(self,@selector(class))。 接受者依然是当前的 phone 这个实例,区别不同的是 它会从父类的方法了列表开始查找,也就是
1 | instance of Subclass --> Superclass(class)-->Root class(class) |
所以依然还是 phone;
消息转发