Objective-C消息转发机制
在看消息转发之前,我们先看一段代码,调用一个 nil 对象方法会咋样?
//Person.h
@interface Person : NSObject
//年龄
- (int)age;
@end
//Person.m
@implementation Person
- (int)age
{
return 18;
}
@end
//调用地方
Person * p = nil;
NSLog(@"my age is :%d",[p age]);要想几个问题,1,会 crash 吗? 为什么,2, log出来的值是18吗? 答案就是不会 crash 因为OC的函数调用都是通过objc_msgSend进行消息发送来实现的,相对于C和C++来说,对于空指针的操作会引起Crash的问题,而objc_msgSend会通过判断self来决定是否发送消息,如果self为nil,那么selector也会为空,直接返回,所以不会出现问题。视方法返回值,向nil发消息可能会返回nil(返回值为对象)、0(返回值为一些基础数据类型)或0X0(返回值为id)等,同时不能输出18. 使用clang -rewrite-objc xxxx.m 可以把一个类编译.
在如下代码,在MRC下创建别一个 p2 对象
猜一下会咋样?会看到
what? why? どういう意味ですか? 原因:一个对象已经被释放了,那么这个时候再去调用方法肯定是会Crash的,因为这个时候这个对象就是一个野指针(指向僵尸对象的指针)了,安全的做法是释放后将对象重新置为nil,使它成为一个空指针即 p2 = nil;
运行后会出现这个错误
run方法在调用时,系统会查看这个对象能否接收这个消息(没有实现这个方法),如果不能接收,就会调用下面这几个方法,给你“补救”的机会,你可以先理解为几套防止程序crash的备选方案,我们就是利用这几个方案进行消息转发,注意一点,前一套方案实现后一套方法就不会执行。如果这几套方案你都没有做处理,那么程序就会crash。 让程序不 crash 的方法 要用到 oc 的 消息转发机制 (message forwarding) 
方案一 动态方法解析 :
class_addMethod 方法说明
types 参考表,如果你想让该方法选择器被传送到转发机制,那么就让resolveInstanceMethod:返回NO
方案二:消息重定向,
这个方案可以把消息转给其他对象, 换个说法就是人类处理不了这方法,让猴子类(其它类)来处理这个方法,有同学是不是想问猴子类也没有实现这个 run 方法咋办,代码会 crash 给你看
这样把消息重定向给Monkey classe 来处理 程序就不会 crash 了
方案三:消息转发
也是改变调用对象,使该消息在新对象上调用;不同是forwardInvocation方法带有一个NSInvocation对象,这个对象保存了这个方法调用的所有信息,包括SEL,参数和返回值描述等,JSPatch就是基于消息转发实现的,这一步需要实现两个方法:
小结
使用场景比如在 crash 之前 弹出一个aleart"数据出现异常需要重启 APP" 比崩用户一脸体验好一些.
当接收无法处理的 selector 时,则进入消息转发流程
消息转发流程可分为两阶段,一共有 3 次机会来处理未知的 selector
第一阶段为 动态方法解析 阶段,用来为类动态添加方法,第二阶段才是正在的消息转发阶段,该阶段可以将未知的 selector 转发到一个或者多个对象中来处理
消息转发流程完成后,都不做任何处理的话,这进入 doesNotRecognizeSelector 方法从而抛出异常
如果将消息转发到其他对象来处理,则需要重写 respondsToSelector 方法来保证该方法正常工作
NSProxy 类是基于消息转发机制来实现的动态代理模式
消息转发机制可用来实现 @dynamic 属性、代理模式、多重继承等
其它资料:
Last updated