*main.m
PersonA *personA = [[PersonA alloc]init];
[personA speechJapan];
- PersonB.h
- (void)speechJapan;
- PersonB.m
- (void)speechJapan{
NSLog(@"speechJapan");
}
- PersonA.h
- (void)speechEnglish;
- (void)speechJapan;
- PersonA.m
- (void)speechEnglish{
NSLog(@"speechEnglist");
}
// 此方法不是方法的实现,需要进行转化
- (void)speechNewLan{
NSLog(@"speechNewLan");
}
// 将方法转换成方法的实现IMP
IMP convertToIMP(){
return class_getMethodImplementation([PersonA class], @selector(speechNewLan));
}
/* 当未找到speechJapan时,首先调用此方法,使有机会添加一个实现的方法
如果添加了方法并且放回了Yes,则运行时系统会启用一次消息发送的过程。如果返回为NO,
运行时系统则进入到下一步,消息转发(Message Forwarding)
*/
// 消息派发
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(speechJapan)) {
class_addMethod(self, sel, convertToIMP(), "");
return YES;
}
return NO;
}
/*实现此方法,运行时系统就会调用次方法,将消息转发给其他指定的对象,
比如转发给PersonB的对象
注:只要返回的对象不是nil或self,消息发送的整个过程就会启动
发送的对象变为指定返回的对象,比如PersonB。如果返回的是nil或self,则进行下一步转发操作
*/
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(speechJapan)) {
PersonB *pB = [[PersonB alloc] init];
return pB;
}
return [super forwardingTargetForSelector:aSelector];
}
// 消息转发第二步 Mormal forwrading
/* 获取方法签名
调用此方法获取函数的参数和返会类型,如果此方法返回nil
Runtime则会发出doseNotRecognizeSelector: 消息挂掉程序
如果返回一个函数签名,Runtime则会创建一个NSINvocation对象,调用ForwradInvacation:
发送消息给对象
*/
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSMethodSignature *sign = [[PersonB class] instanceMethodSignatureForSelector:aSelector];
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
// 实现消息的转发
/*
NSInvocation 实际上是对一个消息的描述,包括selector极其参数等信息
所以可以在此方法中修改NSInvocation对象,然后调用invokeWithTarget:消息给对象
*/
- (void)forwardInvocation:(NSInvocation *)anInvocation{
SEL sel = anInvocation.selector;
PersonB *pB = [[PersonB alloc] init];
if ([pB respondsToSelector:sel]) {
[anInvocation invokeWithTarget:pB];
}else{
[self doesNotRecognizeSelector:sel];
}
}