参考资料:
消息转发流程:
在Objective-c一文中说到,对象在函数列表中找不到SEL或者找不到SEL对应的IMP实现的时候就会进入消息转发流程。流程如下:
图中的IML的意思应该就是“ Objective-c 消息是什么”文章中的通过SEL 查找IMP实现的过程。
+(BOOL)resolveInstanceMethod:(SEL)sel 方法拦截消息
这个消息拦截的作用在于给个机会给本对象动态添加需要的selector。
先来看个例子:
Fish类:
#import <Foundation/Foundation.h>
@interface Fish : NSObject
-(void)fishDescribeYouSelf;
@end
#import "Fish.h"
#import <objc/message.h>
@implementation Fish
-(void)fishDescribeYouSelf{
NSLog(@"I am fish");
}
-(void)_fishMethodNotExit{
NSLog(@"_fishMethodNotExit");
}
//查找动态指定的IMP
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == NSSelectorFromString(@"fishMethodNotExit")) {
IMP _fishMethodNotExit = [Fish instanceMethodForSelector:@selector(_fishMethodNotExit)];
class_addMethod([self class], sel, _fishMethodNotExit, "v@:"); //v@: 第一个字符代表返回的值是void,@是self的类型id,:是_cmd的类型SEL。(Objective-c中的方法默认被隐藏了两个参数:self指向对象本身,_cmd指向方法本身)。如果是@@:则代表返回值是字符串,f@:代表返回值是浮点型
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
调用:
Fish *fish = [[Fish alloc] init];
[fish fishMethodNotExit];
程序不会崩溃并且输出:_fishMethodNotExit。找不到fishMethodNotExit的时候,系统调用了 resolveInstanceMethod,并且给找不到的SEL动态添加了IMP,使得调用_fishMethodNotExit这个函数。
-(id)forwardingTargetForSelector:(SEL)aSelector 拦截消息并且处理
没有在resolveInstanceMethod实现相关的动态添加,不管返回值是否为YES,消息则会来到快速转发forwardingTargetForSelector。
这个消息拦截的作用在于,给个机会把消息转发给另外一个对象
看例子,新增一个Flower类:
#import <Foundation/Foundation.h>
@interface Flower : NSObject
-(void)fishMethodNotExit;
@end
@implementation Flower
-(void)fishMethodNotExit{
NSLog(@"fishMethodNotExit in Flower");
}
@end
去掉Fish类的resolveInstanceMethod,添加forwardingTargetForSelector的实现。
-(id)forwardingTargetForSelector:(SEL)aSelector{
Flower *flower = [[Flower alloc] init];
if ([flower respondsToSelector:aSelector]) {
return flower;
}
return self;
}
调用:
Fish *fish = [[Fish alloc] init];
[fish fishMethodNotExit];
输出:
fishMethodNotExit in Flower
如果resolveInstanceMethod 和 forwardingTargetForSelector没有对消息进行处理,则来到标准转发