描述:如果类不能执行这个方法,会执行动态消息转发,如果该类还是不能动态的添加方法,则走完整的消息转发。分两步,第一步看看有没有其他类可以执行该方法,如果没有走第二步,将所有的细节封装到NSInvocation中,给接受者最后一次机会

演示: 动态消息转发 >在一个类MessageObj中定义两个方法,testDynamicMethodForward一个有实现方法,start一个没有实现的方法,调用没有实现的方法,在动态消息转发的时候将这个方法hook到已经实现的方法上:

@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

完整的消息转发第一步 >定义两个类,第一个类MessageObj有一个未实现的方法start,并且没有实现动态消息转发。第二个类OtherClass,有一个和第一个类中未实现的方法同名的方法start,在进行完整消息转发的第一步时,将MessageObj中未实现的方法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

完整消息转发的第二步 如果以上两步都失败了,就走到这里。定义两个类MessageObjOtherClassMessageObj中存在OtherClass的实例。当走到消息转发的第三步时,先进行方法重签名-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector,再走最后的消息转发-(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;
}
//最后的消息转发
-(void)forwardInvocation:(NSInvocation *)anInvocation {
    if (!otherClass) {
        [self doesNotRecognizeSelector:[anInvocation selector]];
    }
    [anInvocation invokeWithTarget:otherClass];
}

打印:message transform third part OtherClass

用途: - 在方法不能识别的时候做一些保护,防止crash - 调试的时候打印一些感兴趣的日志 - 也可以hook系统的方法玩玩呀