??好的!今天我們來練習(xí)IOS花墩,當(dāng)消息發(fā)送給沒有實(shí)現(xiàn)該消息方法的對象時,會開始消息轉(zhuǎn)發(fā)流程:動態(tài)方法解析->尋找備用接收者->消息轉(zhuǎn)發(fā)祠肥,要是這三個步驟都沒有進(jìn)行未實(shí)現(xiàn)方法的處理,會拋出異常剂桥。
動態(tài)方法解析
??首先我們暴露了Dog類的talk,callBaaBaa斟薇,callMeowMeow實(shí)例方法,但是Dog類沒有實(shí)現(xiàn)這些方法椿猎,所以當(dāng)dog對象調(diào)用它們就會奔潰,因此在resolveInstanceMethod方法中我們需要為dog對象添加talk實(shí)例方法(是人類的talk方法)筐咧。
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if([NSStringFromSelector(sel) isEqualToString:@"talk"]) {
//因為狗類沒有實(shí)現(xiàn)talk方法量蕊,在動態(tài)方法解析時為狗類增加說話的此方法
class_addMethod([self class], @selector(talk), class_getMethodImplementation([Humanity class], @selector(talk)), "v@:");
}
return [super resolveInstanceMethod:sel];
}
尋找備用接收者
??然后dog對象調(diào)用callBaaBaa方法残炮,同樣它沒有實(shí)現(xiàn)該方法,也沒有在resolveInstanceMethod中添加callBaaBaa方法缩滨,在調(diào)用完resolveInstanceMethod后势就,會進(jìn)行forwardingTargetForSelector方法,因此我們在forwardingTargetForSelector尋找羊類作為callBaaBaa的備用接收者防止奔潰脉漏。
- (id)forwardingTargetForSelector:(SEL)aSelector {
//備用接收者羊處理消息
if([NSStringFromSelector(aSelector) isEqualToString:@"callBaaBaa"]) {
return sheep;
}
return [super forwardingTargetForSelector:aSelector];
}
消息轉(zhuǎn)發(fā)
??最后我們的dog對象調(diào)用了沒有實(shí)現(xiàn)的callMeowMeow方法苞冯,當(dāng)進(jìn)行完forwardingTargetForSelector方法之后會調(diào)用forwardInvocation方法進(jìn)行消息轉(zhuǎn)發(fā)的處理舅锄,所以我們在forwardInvocation中將消息轉(zhuǎn)發(fā)給貓類防止奔潰。
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = [anInvocation selector];
if([super respondsToSelector:sel]) {
[super forwardInvocation:anInvocation];
} else {
[anInvocation invokeWithTarget:cat];//轉(zhuǎn)發(fā)給貓類
}
}
//重寫methodSignatureForSelector,創(chuàng)建要轉(zhuǎn)發(fā)的NSInvocation對象
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if([super respondsToSelector:aSelector]) {
return [super methodSignatureForSelector:aSelector];
} else {
return [cat methodSignatureForSelector:aSelector];
}
}
最后刃泡,完整代碼鏈接:https://github.com/arrosev/CMDTestProject