說(shuō)到runtime,就不得不講到最重要的消息轉(zhuǎn)發(fā)機(jī)制,轉(zhuǎn)發(fā)的流程圖如下:

在OC里面,所有的方法調(diào)用,在運(yùn)行時(shí)的時(shí)候都可以看作是objc_msgSend(obj,@selector())的調(diào)用
1.正常的方法調(diào)用
person.h文件,聲明方法
#import <Foundation/Foundation.h>
@interface Person : NSObject
-(void)sendMessage:(NSString *)msg;
@end
person.m文件
#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person
- (void)sendMessage:(NSString *)msg{
NSLog(@"person send msg:%@",msg);
}
@end
如果person.m實(shí)現(xiàn)了-(void)sendMessage:(NSString *)msg 方法,那么將會(huì)調(diào)用該方法,結(jié)果如圖:

如果沒(méi)有實(shí)現(xiàn)這個(gè)方法,則會(huì)報(bào)錯(cuò)沒(méi)有該方法

那么實(shí)現(xiàn)消息轉(zhuǎn)發(fā)機(jī)制的方法,就可以解決這個(gè)問(wèn)題:
- 如果沒(méi)有實(shí)現(xiàn)改方法,會(huì)先進(jìn)行動(dòng)態(tài)解析,調(diào)用+ (BOOL)resolveInstanceMethod:(SEL)sel方法
#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person
//- (void)sendMessage:(NSString *)msg{
// NSLog(@"person send msg:%@",msg);
//}
void sendMessage(id self,SEL _cmd,NSString *msg) {
NSLog(@"send msg:%@",msg);
}
//動(dòng)態(tài)解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"動(dòng)態(tài)方法解析");
NSString *methodName = NSStringFromSelector(sel);
if ([methodName isEqualToString:@"sendMessage:"]) {
return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
}
return NO;
}
@end

2.如果第一步的動(dòng)態(tài)解析也沒(méi)有找到方法,那么將會(huì)進(jìn)行快速轉(zhuǎn)發(fā),調(diào)用- (id)forwardingTargetForSelector:(SEL)aSelector可以在本類(lèi)方法列表未找到方法的時(shí)候,轉(zhuǎn)發(fā)給其他類(lèi),并返回該類(lèi)對(duì)象:
Child.m 文件實(shí)現(xiàn)了一個(gè)方法
#import "Child.h"
@implementation Child
- (void)sendMessage:(NSString *)msg{
NSLog(@"child send msg:%@",msg);
}
@end
#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person
//- (void)sendMessage:(NSString *)msg{
// NSLog(@"person send msg:%@",msg);
//}
//void sendMessage(id self,SEL _cmd,NSString *msg) {
// NSLog(@"send msg:%@",msg);
//}
//動(dòng)態(tài)解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
// NSLog(@"動(dòng)態(tài)方法解析");
// NSString *methodName = NSStringFromSelector(sel);
// if ([methodName isEqualToString:@"sendMessage:"]) {
// return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
// }
return NO;
}
//快速轉(zhuǎn)發(fā)
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSString *methodName = NSStringFromSelector(aSelector);
if ([methodName isEqualToString:@"sendMessage:"]) {
return [Child new];
}
return [super forwardingTargetForSelector:aSelector];
}
@end
運(yùn)行結(jié)果:

3.如果沒(méi)有快速轉(zhuǎn)發(fā)也失敗了,那么將會(huì)返回nil,進(jìn)行慢速轉(zhuǎn)發(fā),慢速轉(zhuǎn)發(fā)需要實(shí)現(xiàn)兩個(gè)方法:
(1)- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
(2) - (void)forwardInvocation:(NSInvocation *)anInvocation
#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person
//- (void)sendMessage:(NSString *)msg{
// NSLog(@"person send msg:%@",msg);
//}
//void sendMessage(id self,SEL _cmd,NSString *msg) {
// NSLog(@"send msg:%@",msg);
//}
//動(dòng)態(tài)解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
// NSLog(@"動(dòng)態(tài)方法解析");
// NSString *methodName = NSStringFromSelector(sel);
// if ([methodName isEqualToString:@"sendMessage:"]) {
// return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
// }
return NO;
}
//快速轉(zhuǎn)發(fā)
- (id)forwardingTargetForSelector:(SEL)aSelector{
// NSString *methodName = NSStringFromSelector(aSelector);
// if ([methodName isEqualToString:@"sendMessage:"]) {
// return [Child new];
// }
return [super forwardingTargetForSelector:aSelector];
}
//慢速轉(zhuǎn)發(fā) 1.簽名 2.轉(zhuǎn)發(fā)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSString *methodName = NSStringFromSelector(aSelector);
if ([methodName isEqualToString:@"sendMessage:"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
SEL sel = anInvocation.selector;
Child *child = [Child new];
if ([child respondsToSelector:sel]) {
[anInvocation invokeWithTarget:child];
}else {
[super forwardInvocation:anInvocation];
}
}
結(jié)果如下,還是轉(zhuǎn)發(fā)給了child的類(lèi)對(duì)象,消息轉(zhuǎn)發(fā)成功:

4.最后,如果消息轉(zhuǎn)發(fā)失敗,那么將會(huì)報(bào)錯(cuò),但是為了程序防止崩潰,還是有方法可以處理的,因?yàn)榈阶詈笕绻€沒(méi)有轉(zhuǎn)發(fā)成功,那么將會(huì)走-(void)doesNotRecognizeSelector:(SEL)aSelector方法:
#import "Person.h"
#import "Child.h"
#import <objc/runtime.h>
@implementation Person
//- (void)sendMessage:(NSString *)msg{
// NSLog(@"person send msg:%@",msg);
//}
//void sendMessage(id self,SEL _cmd,NSString *msg) {
// NSLog(@"send msg:%@",msg);
//}
//動(dòng)態(tài)解析
+ (BOOL)resolveInstanceMethod:(SEL)sel{
// NSLog(@"動(dòng)態(tài)方法解析");
// NSString *methodName = NSStringFromSelector(sel);
// if ([methodName isEqualToString:@"sendMessage:"]) {
// return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");
// }
return NO;
}
//快速轉(zhuǎn)發(fā)
- (id)forwardingTargetForSelector:(SEL)aSelector{
// NSString *methodName = NSStringFromSelector(aSelector);
// if ([methodName isEqualToString:@"sendMessage:"]) {
// return [Child new];
// }
return [super forwardingTargetForSelector:aSelector];
}
//慢速轉(zhuǎn)發(fā) 1.簽名 2.轉(zhuǎn)發(fā)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSString *methodName = NSStringFromSelector(aSelector);
if ([methodName isEqualToString:@"sendMessage:"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
// SEL sel = anInvocation.selector;
// Child *child = [Child new];
// if ([child respondsToSelector:sel]) {
// [anInvocation invokeWithTarget:child];
// }else {
// [super forwardInvocation:anInvocation];
// }
[super forwardInvocation:anInvocation];
}
-(void)doesNotRecognizeSelector:(SEL)aSelector{
NSLog(@"無(wú)法識(shí)別該消息:%@",NSStringFromSelector(aSelector));
}
@end
運(yùn)行結(jié)果:

到此一個(gè)完整的消息轉(zhuǎn)發(fā)機(jī)制例子就演示完畢了,如果有需要的可以下載完整的源碼,本文也是參考了部分大神的文章,對(duì)自己的一個(gè)小結(jié),如果有誤導(dǎo)的地方,歡迎大家指正以及補(bǔ)充***