消息转发机制:
消息转发机制是相对于消息传递机制而言的。
1、消息(传递)机制
RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。
对于C语言,函数的调用在编译的时候会决定调用哪个函数。编译完成之后直接顺序执行,无任何二义性。OC的函数调用称为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(也就是说,在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
[obj makeText];
首先,编译器将代码[obj makeText];
转化为objc_msgSend(obj, @selector (makeText));
,在objc_msgSend
函数中。首先通过obj
的isa
指针找到obj
对应的class
。在Class
中先去cache
中 通过SEL
查找对应函数method
,若 cache
中未找到。再去methodList
中查找,若methodlist
中未找到,则取superClass
中查找。若能找到,则将method
加入到cache
中,以方便下次查找,并通过method
中的函数指针跳转到对应的函数中去执行。
2、消息转发机制(可以间接实现多重继承)

当向
someObject
发送某消息,但runtime
在当前类和父类中都找不到对应方法的实现时,runtime
并不会立即报错使程序崩溃,而是依次执行下列步骤:
-
动态方法解析:向当前类发送
resolveInstanceMethod:
信号,检查是否动态向该类添加了方法。(迷茫请搜索:@dynamic) -
快速消息转发:检查该类是否实现了
forwardingTargetForSelector:
方法,若实现了则调用这个方法。若该方法返回值对象非nil或非self,则向该返回对象重新发送消息。 -
标准消息转发:
runtime
发送methodSignatureForSelector
消息获取Selector
对应的方法签名。返回值非空则通过forwardInvocation:
转发消息,返回值为空则向当前对象发送doesNotRecognizeSelector:
消息,程序崩溃退出。
这样如果本类中没有的方法,就会去class中尝试查找,如果有,则返回class
对象,让其执行,这样就实现了快速消息转发
第一个阶段,动态方法解析
#import "ViewController.h"
#import "objc/runtime.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:@selector(foo:)];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(foo:)) {
class_addMethod([self class], sel, (IMP)fooMethod, "v@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
void fooMethod(id obj, SEL _cmd){
NSLog(@"Doing foo");
}
第二个阶段,快速消息转发:
#import "ViewController.h"
#import "objc/runtime.h"
@interface Person : NSObject
@end
@implementation Person
- (void)foo{
NSLog(@"Doing foo");
}
@end
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:@selector(foo)];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
return YES;// 返回YES进入下一步转发
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(foo)) {
return [Person new]; // 返回Person对象,让Person对象接受这个消息
}
return [super forwardingTargetForSelector:aSelector];
}
@end
第三个阶段:标准消息转发
#import "ViewController.h"
#import "objc/runtime.h"
@interface Person : NSObject
@end
@implementation Person
- (void)foo{
NSLog(@"Doing foo");
}
@end
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:@selector(foo)];
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
return YES;// 返回YES进入下一步转发
}
- (id)forwardingTargetForSelector:(SEL)aSelector{
return nil;// 返回nil进入下一步转发
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
SEL sel = anInvocation.selector;
Person *p = [Person new];
if ([p respondsToSelector:sel]) {
[anInvocation invokeWithTarget:p];
}else{
[self doesNotRecognizeSelector:sel];
}
}
@end
以上打印结果:Doing foo
网友评论