(以最新runtime.h源码为例,objc4-723)
当调用一个方法[ object sendMessage ]的时候,会发生如下情况:
(1)首先会根据接收器对象的isa指针获取object的所属的类别Class,比如NSObject类。
(2)优先从这个类中的cache里查找sendMessage方法,如果找不到,就会在methodList里面去找。
(3)如果当前Class没找到,就会去super_class里面继续找。
class.png
一、找得到的情况
(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地址












网友评论