消息发送和消息转发

消息发送

消息发送举例:下面这个OC代码

[person read:book]

会被编译成:

objc_msgSend(person, @selector(read:), book);

objc_msgSend的具体流程如下:

消息转发

上面我们提到, 如果到最后都找不到, 就会来到消息转发,消息转发的流程如下:

对象在收到无法解读的消息后, 首先调用其所属类的这个类方法 :

objc_msgSend(person, @selector(read:), book);

假如尚未实现的方法不是实例方法而是类方法, 则会调用另一个方法resolveClassMethod:

2. 备胎

动态方法解析失败, 则调用这个方法

- (id)forwardingTargetForSelector:(SEL)selector
// selector : 那个未知的消息
// 返回一个能响应该未知选择子的备胎对象

通过备胎这个方法, 可以用”组合”来模拟出”多重继承”.

3. 消息签名

备胎搞不定, 这个方法就准备要被包装成一个NSInvocation对象, 在这里要先返回一个方法签名

- (id)forwardingTargetForSelector:(SEL)selector
// selector : 那个未知的消息
// 返回一个能响应该未知选择子的备胎对象

4. 完整的消息转发

给接收者最后一次机会把这个方法处理了, 搞不定就直接程序崩溃!

- (id)forwardingTargetForSelector:(SEL)selector
// selector : 那个未知的消息
// 返回一个能响应该未知选择子的备胎对象

在这里能做的比较现实的事就是 : 在触发消息前, 先以某种方式改变消息内容, 比如追加另外一个参数, 或是改变消息等等. 实现此方法时, 如果发现某调用操作不应该由本类处理, 可以调用超类的同名方法. 则继承体系中的每个类都有机会处理该请求, 直到NSObject. 如果NSObject搞不定, 则还会调用doesNotRecognizeSelector:来抛出异常, 此时你就会在控制台看到那熟悉的unrecognized selector sent to instance..

上面这4个方法均是模板方法,开发者可以override,由runtime来调用。最常见的实现消息转发,就是重写方法3和4,忽略这个消息或者代理给其他对象.