简书:http://www.jianshu.com/u/5690b3ad0a6f
Blog:http://blog.zhangpeng.site
GitHub:https://github.com/fullstack-zhangpeng
消息转发
当对象接收到无法解读的消息(unrecognized selector sent to instance 0x87
),就会启动消息转发机制,由程序员指定处理方法。
消息转发机制
消息转发两大阶段
-
动态方法解析
检查当前接收者能否动态添加方法,处理这个
unrecognized selector
。 -
完整的消息转发
第一阶段执行完毕后,如接收者不能以动态新增方法处理这个
unrecognized selector
,接下来,会分两种情况:-
有备援接收者(replacement receiver)
在运行期将消息转给备援接收者,由备援接收者完成消息的处理。
-
无备援接收者(replacement receiver)
启动一套“完整的消息转发机制”,将消息封装到NSInvocation对象中,交给接收者处理。
-
动态方法解析
如果没有找到需要执行的方法,会根据方法的类型,执行不同的处理方法。
处理无法调用的类方法
+ (BOOL)resolveClassMethod:(SEL)sel
处理无法调用的实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
一般是提前写好相关的实现代码,通过Runtime在此处插入到类中。
e.g.
/**
没有找到SEL的实现时会执行下方的方法
@param sel 当前对象调用并且找不到IML的SEL
@return 是否可以处理这个方法,并返回yes
*/
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// 当返回YES时
// 在这里通过Runtime在将已经写好实现的代码插入到类中。
// ...
return YES;
// 当返回NO时
// 会接着执行forwordingTargetForSelector:方法
// return NO;
}
消息转发
有备援接收者
在方法- (id)forwardingTargetForSelector:(SEL)aSelector
中返回可以处理该消息的对象,交由该对象去处理这个消息。
如果此处返回nil,则表示没有其他对象可以处理这个消息,然后通过完整的消息转发机制来处理。
/**
将当前对象不存在的SEL传给其他存在该SEL的对象
@param aSelector 当前类中不存在的SEL
@return 存在该SEL的对象
*/
- (id)forwardingTargetForSelector:(SEL)aSelector
{
// 不传递给其他对象
// 将会执行- (void)forwardInvocation:(NSInvocation *)anInvocation;
return nil;
// 传递给一个其他对象,处理这个方法。
// 可以做相应的错误处理等
// 让OtherClass中相应的SEL去执行该方法
// return [[OtherClass alloc] init];
}
无备援接收者
如果接收者不能处理消息,并且没有备援接收者,最终只能采取一个完整的消息转发来处理消息。
通过NSInvocation包装方法的目标、参数等,然后通过- (void)forwardInvocation:(NSInvocation *)invocation
将消息指派给目标对象。
- (void)forwardInvocation:(NSInvocation *)invocation
{
SecondClass * forwardClass = [SecondClass new];
SEL sel = invocation.selector;
if ([forwardClass respondsToSelector:sel]) {
[invocation invokeWithTarget:forwardClass];
} else {
[self doesNotRecognizeSelector:sel];
}
}
网友评论