消息轉發(fā)
描述:如果類不能執(zhí)行這個方法祭芦,會執(zhí)行動態(tài)消息轉發(fā)移层,如果該類還是不能動態(tài)的添加方法仍翰,則走完整的消息轉發(fā)。分兩步观话,第一步看看有沒有其他類可以執(zhí)行該方法予借,如果沒有走第二步,將所有的細節(jié)封裝到NSInvocation中频蛔,給接受者最后一次機會灵迫。
演示:
動態(tài)消息轉發(fā)
在一個類
MessageObj
中定義兩個方法,testDynamicMethodForward
一個有實現(xiàn)方法晦溪,start
一個沒有實現(xiàn)的方法瀑粥,調用沒有實現(xiàn)的方法,在動態(tài)消息轉發(fā)的時候將這個方法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
完整的消息轉發(fā)第一步
定義兩個類三圆,第一個類
MessageObj
有一個未實現(xiàn)的方法start
狞换,并且沒有實現(xiàn)動態(tài)消息轉發(fā)。第二個類OtherClass
嫌术,有一個和第一個類中未實現(xiàn)的方法同名的方法start
哀澈,在進行完整消息轉發(fā)的第一步時,將MessageOb
j中未實現(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;
}
調用start
方法
MessageObj *obj = [MessageObj new];
[obj start];
打痈畎础:do some thing OtherClass
完整消息轉發(fā)的第二步
如果以上兩步都失敗了,就走到這里磷籍。定義兩個類MessageObj
适荣、OtherClass
现柠,MessageObj
中存在OtherClass
的實例。當走到消息轉發(fā)的第三步時弛矛,先進行方法重簽名-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
够吩,再走最后的消息轉發(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;
}
//最后的消息轉發(fā)
-(void)forwardInvocation:(NSInvocation *)anInvocation {
if (!otherClass) {
[self doesNotRecognizeSelector:[anInvocation selector]];
}
[anInvocation invokeWithTarget:otherClass];
}
打诱擅ァ:message transform third part OtherClass
用途:
- 在方法不能識別的時候做一些保護周循,防止crash
- 調試的時候打印一些感興趣的日志
- 也可以hook系統(tǒng)的方法玩玩呀