在iOS中,如果遇到消息无法处理。(例如在头文件中声明了该方法,但是在m文件中没有实现该方法).对方法发生调用后,系统会依照从当前类、当前类的父类、父类的父类...这个顺序进行查找这个方法,如果递归直至根类都没能处理这个方法。在系统发生cash之前,会先启动消息转发机制。试图对该消息进行处理。
动态方法解析
+ (BOOL)resolveInstanceMethod:(SEL)sel;
在本类内部寻找选择子sel 的方法;
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(eat)) {
class_addMethod(self, sel, (IMP)eatMeat, "v@:@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
-(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(eat)) {
class_addMethod(self, sel, (IMP)eatMeat, "v@:@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
用这个方法的前提是本类内部已经实现了eatMeat方法。如果eatMeat依然不存在,则会进入 备援接受者寻找处理方法。
备援接收者(快速消息转发)
如果本类动态方法解析无法处理则可以把处理方法交给其他接受者。在forwordingTargetForSelector方法中重新初始化一个类,并该类中调用该方法,前提是该类中有这个方法。如果处理不了,会向父类去寻找该方法,直到NSObject。如果备援接受者确定处理不了该方法,将会进入完整的消息转发。
- (id)forwordingTargetForSelector:(SEL)aSelector;
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSString *selectorStr = NSStringFromSelector(aSelector);//获取消息的选择子
if ([selectorStr isEqualToString:@"eat"]) {
AnimalForwardingTarget *action = [AnimalForwardingTarget new];
return action;
}
return [super forwardingTargetForSelector:aSelector];
}
id)forwardingTargetForSelector:(SEL)aSelector{
NSString *selectorStr = NSStringFromSelector(aSelector);//获取消息的选择子
if ([selectorStr isEqualToString:@"eat"]) {
AnimalForwardingTarget *action = [AnimalForwardingTarget new];
return action;
}
return [super forwardingTargetForSelector:aSelector];
}
完整的消息转发
生成方法签名
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector;
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
NSString *selectedStr = NSStringFromSelector(aSelector); //获取消息的选择子
if ([selectedStr isEqualToString:@"eat"]) {
NSMethodSignature *sign = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
return sign;
}
return [super methodSignatureForSelector:aSelector];
}
NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
NSString *selectedStr = NSStringFromSelector(aSelector); //获取消息的选择子
if ([selectedStr isEqualToString:@"eat"]) {
NSMethodSignature *sign = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
return sign;
}
return [super methodSignatureForSelector:aSelector];
}
利用签名生成NSInnovation
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"]; //利用签名生成NSInnovation
anInvocation = [NSInvocation invocationWithMethodSignature: signature];
[anInvocation setTarget: self];
anInvocation.selector = NSSelectorFromString(@"eatDogFood");
AnimalForwardInvocation* animalInvocation = [AnimalForwardInvocation new];
if ([animalInvocation respondsToSelector:[anInvocation selector]]) { //如果AnimalForwardInvovation这个类中实现了选择子eatDogFood
[anInvocation invokeWithTarget: animalInvocation];
} else {
[super forwardInvocation: anInvocation];
}
}
void)forwardInvocation:(NSInvocation *)anInvocation{
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"]; //利用签名生成NSInnovation
anInvocation = [NSInvocation invocationWithMethodSignature: signature];
[anInvocation setTarget: self];
anInvocation.selector = NSSelectorFromString(@"eatDogFood");
AnimalForwardInvocation* animalInvocation = [AnimalForwardInvocation new];
if ([animalInvocation respondsToSelector:[anInvocation selector]]) { //如果AnimalForwardInvovation这个类中实现了选择子eatDogFood
[anInvocation invokeWithTarget: animalInvocation];
} else {
[super forwardInvocation: anInvocation];
}
}
如果连完整的消息转发也处理不了该方法,系统会发生cash.