消息轉(zhuǎn)發(fā)
描述:如果類不能執(zhí)行這個方法,會執(zhí)行動態(tài)消息轉(zhuǎn)發(fā),如果該類還是不能動態(tài)的添加方法,則走完整的消息轉(zhuǎn)發(fā)。分兩步,第一步看看有沒有其他類可以執(zhí)行該方法,如果沒有走第二步,將所有的細(xì)節(jié)封裝到NSInvocation中,給接受者最后一次機會。
演示:
動態(tài)消息轉(zhuǎn)發(fā)
在一個類
MessageObj中定義兩個方法,testDynamicMethodForward一個有實現(xiàn)方法,start一個沒有實現(xiàn)的方法,調(diào)用沒有實現(xiàn)的方法,在動態(tài)消息轉(zhuǎn)發(fā)的時候?qū)⑦@個方法hook到已經(jīng)實現(xiàn)的方法上:
@interface MessageObj()
@end
@implementation MessageObj
//-(void)start{}
void testDynamicMethodForward(){
printf("testDynamicMethodForward \n");
}
+(BOOL)resolveInstanceMethod:(SEL)sel {
class_addMethod([self class], sel, (IMP)testDynamicMethodForward, "v@@:");
return YES;
}
@end
打印如下:testDynamicMethodForward
完整的消息轉(zhuǎn)發(fā)第一步
定義兩個類,第一個類
MessageObj有一個未實現(xiàn)的方法start,并且沒有實現(xiàn)動態(tài)消息轉(zhuǎn)發(fā)。第二個類OtherClass,有一個和第一個類中未實現(xiàn)的方法同名的方法start,在進行完整消息轉(zhuǎn)發(fā)的第一步時,將MessageObj中未實現(xiàn)的方法hook到,OtherClass的同名方法start中
OtherClass類
@interface OtherClass : NSObject
@end
@implementation OtherClass
-(void)start{
NSLog(@"do some thing %@",[self class]);
}
@end
MessageObj類
@implementation MessageObj
//-(void)start{}
-(id)forwardingTargetForSelector:(SEL)aSelector {
printf("%p \n",&aSelector);
OtherClass *obj = [OtherClass new];
return obj;
}
調(diào)用start方法
MessageObj *obj = [MessageObj new];
[obj start];
打?。篸o some thing OtherClass
完整消息轉(zhuǎn)發(fā)的第二步
如果以上兩步都失敗了,就走到這里。定義兩個類MessageObj、OtherClass,MessageObj中存在OtherClass的實例。當(dāng)走到消息轉(zhuǎn)發(fā)的第三步時,先進行方法重簽名-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector,再走最后的消息轉(zhuǎn)發(fā)-(void)forwardInvocation:(NSInvocation *)anInvocation。
OtherClass類
@interface OtherClass : NSObject
@end
@implementation OtherClass
-(void)start{
NSLog(@"message transform third part %@",[self class]);
}
@end
MessageObj類
@implementation MessageObj
-(instancetype)init {
if (self = [super init]) {
otherClass = [OtherClass new];
}
return self;
}
//-(void)start{}
//方法重簽名
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if (!signature) {
signature = [otherClass methodSignatureForSelector:aSelector];
}
return signature;
}
//最后的消息轉(zhuǎn)發(fā)
-(void)forwardInvocation:(NSInvocation *)anInvocation {
if (!otherClass) {
[self doesNotRecognizeSelector:[anInvocation selector]];
}
[anInvocation invokeWithTarget:otherClass];
}
打印:message transform third part OtherClass
用途:
- 在方法不能識別的時候做一些保護,防止crash
- 調(diào)試的時候打印一些感興趣的日志
- 也可以hook系統(tǒng)的方法玩玩呀