(以最新runtime.h源码为例,objc4-723)
当调用一个方法[ object sendMessage ]
的时候,会发生如下情况:
(1)首先会根据接收器对象的isa指针
获取object
的所属的类别Class
,比如NSObject
类。
(2)优先从这个类中的cache
里查找sendMessage
方法,如果找不到,就会在methodList
里面去找。
(3)如果当前Class
没找到,就会去super_class
里面继续找。
一、找得到的情况
(1)如果找到了method,就会执行他实现的IMP。 method.png二、找不到的情况
开始方法解析和消息转发过程。
(1)Method Resolution
首先会调用+(BOOL)resolveInstanceMethod:(SEL)sel
,你需要做对应的处理,并且返回YES。
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if (sel == @selector(sendMessage)) {
class_addMethod([self class], sel, imp_implementationWithBlock(^(id self) {
NSLog(@"method resolution way : send message");
}), "v@*");
}
return YES;
}
如果返回NO或者什么都不写直接返回YES,就会走(2)。
(2)Fast Forwarding
执行- (id)forwardingTargetForSelector:(SEL)aSelector
,将你调用的不存在的方法重定向到一个其他声明了这个方法的类,只需要你返回一个有这个方法的target,消息转发机制执行前,Runtime 系统允许我们替换消息的接收者为其他对象AnotherClass
。
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == @selector(sendMessage)) {
return [AnotherClass new];
}
return nil;
}
如果return
的是nil
或者self
,那就走(3)
(3)Normal Forwarding
首先调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
来获取你需要调用的sendMessage
的参数和返回值。
如果返回nil
,就直接crash,抛出异常unrecognized selector sent to instance
。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
if (!methodSignature) {
methodSignature = [NSMethodSignature signatureWithObjCTypes:"v@:*"];
}
return methodSignature;
}
如果返回一个NSMethodSignature
,系统就会创建一个NSInvocation
对象(这也就是为什么这里叫Normal,而前面叫Fast),开始调用- (void)forwardInvocation:(NSInvocation *)anInvocation
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
AnotherClass *anotherClass = [AnotherClass new];
if ([anotherClass respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:anotherClass];
}
}
这3种解决找不到方法的路子,优势不一。
Method Resolution:仅是解析处理,只适用于在原来的类Object
中代替。
Fast Forwarding:它可以将消息处理转发给其他对象AnotherClass
。
Normal Forwarding:它跟Fast Forwarding一样可以消息转发,但它能通过NSInvocation
对象获取更多消息发送的信息,例如:target
、selector
、arguments
和返回值
等信息。
demo地址
网友评论