好的!今天我们来练习IOS,当消息发送给没有实现该消息方法的对象时,会开始消息转发流程:动态方法解析->寻找备用接收者->消息转发,要是这三个步骤都没有进行未实现方法的处理,会抛出异常。
动态方法解析
首先我们暴露了Dog类的talk,callBaaBaa,callMeowMeow实例方法,但是Dog类没有实现这些方法,所以当dog对象调用它们就会奔溃,因此在resolveInstanceMethod方法中我们需要为dog对象添加talk实例方法(是人类的talk方法)。
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if([NSStringFromSelector(sel) isEqualToString:@"talk"]) {
//因为狗类没有实现talk方法,在动态方法解析时为狗类增加说话的此方法
class_addMethod([self class], @selector(talk), class_getMethodImplementation([Humanity class], @selector(talk)), "v@:");
}
return [super resolveInstanceMethod:sel];
}
寻找备用接收者
然后dog对象调用callBaaBaa方法,同样它没有实现该方法,也没有在resolveInstanceMethod中添加callBaaBaa方法,在调用完resolveInstanceMethod后,会进行forwardingTargetForSelector方法,因此我们在forwardingTargetForSelector寻找羊类作为callBaaBaa的备用接收者防止奔溃。
- (id)forwardingTargetForSelector:(SEL)aSelector {
//备用接收者羊处理消息
if([NSStringFromSelector(aSelector) isEqualToString:@"callBaaBaa"]) {
return sheep;
}
return [super forwardingTargetForSelector:aSelector];
}
消息转发
最后我们的dog对象调用了没有实现的callMeowMeow方法,当进行完forwardingTargetForSelector方法之后会调用forwardInvocation方法进行消息转发的处理,所以我们在forwardInvocation中将消息转发给猫类防止奔溃。
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = [anInvocation selector];
if([super respondsToSelector:sel]) {
[super forwardInvocation:anInvocation];
} else {
[anInvocation invokeWithTarget:cat];//转发给猫类
}
}
//重写methodSignatureForSelector,创建要转发的NSInvocation对象
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if([super respondsToSelector:aSelector]) {
return [super methodSignatureForSelector:aSelector];
} else {
return [cat methodSignatureForSelector:aSelector];
}
}
网友评论