当发给某个对象的消息在类对象以及所有的父类的方法列表中都找不到时,启用消息转发机制,有三个机会可以处理:
1.方法的动态解析(给未识别的sel动态加一个IMP实现)
即重写resolveInstanceMethod:(SEL)sel( 或 resolveClassMethod,针对类方法)
在这个方法中我们可以给找不到方法的sel动态添加一个方法的实现(即sel对应的IMP实现,一般就是一个普通的C函数的实现,前两个参数分别为id和SEL),然后返回YES,这时候会再走一遍发送消息的流程。
ps:只有真正动态添加了方法的IMP并返回YES,这个消息才算是正确处理了,否则会走下面的流程。
2. 把消息发给备用接收者
重写- (id)forwardingTargetForSelector:(SEL)aSelector 这个方法,即把当前未识别的消息发送给另一个备用对象。
如果这个方法返回nil则继续走第三步的流程。
3.完整的消息转发
runtime会创建一个NSInvocation对象,然后把所有的细节都封装在这个对象里,我们可以改NSInvocation中的所有方法相关的细节,然后再通过NSInvocation调用方法。一般来说是在- (void)forwardInvocation:(NSInvocation *)anInvocation中进行调用。
runtime创建NSInvocation对象时会通过- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 获得方法的签名,如果返回方法签名这一步返回nil,那么同样会触发doesNotRecognizeSelector这个函数并抛出异常。
doesNotRecognizeSelector这个函数有两个地方可能会调用,第一个是methodSignatureForSelector返回nil时,另一个是methodSignatureForSelector不返回空,但是直接调到了根类的forwardInvocation方法并没有任何特殊处理时。
所以在完整的消息转发这一步拦截crash时,两步走,第一步通过methodSignatureForSelector返回一个方法签名,第二步重写forwardInvocation方法,但是在这个方法里什么都不做。
浙公网安备 33010602011771号