【iOS】消息转发机制

【iOS】消息转发机制_第1张图片
消息转发机制图

1、动态方法解析

对象在收到无法处理的消息时,会调用下面的方法,前者是调用类方法时会调用,后者是调用对象方法时会调用。

// 类方法专用

+ (BOOL)resolveClassMethod:(SEL)sel

// 对象方法专用

+ (BOOL)resolveInstanceMethod:(SEL)sel

在该方法中,需要给对象所属类动态的添加一个方法,并返回YES,表明可以处理

void dynamicMethodIMP(id self, SEL _cmd) {    

    NSLog(@" >> dynamicMethodIMP");

}

+ (BOOL)resolveInstanceMethod:(SEL)sel {    

    NSLog(@"%@", NSStringFromSelector(sel));    

    if (sel == @selector(run)) {        

        class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");        

        return YES;    

       }    

    return [super resolveInstanceMethod:sel];

}

2、备援接受者

经历了第一步后,如果该消息还是无法处理,那么就会调用下面的方法,查询是否有其它对象能够处理该消息。

- (id)forwardingTargetForSelector:(SEL)aSelector

在这个方法里,我们需要返回一个能够处理该消息的对象

- (id)forwardingTargetForSelector:(SEL)aSelector {    

    NSLog(@"%@", NSStringFromSelector(aSelector));    

    if (aSelector == @selector(run)) {        

        Animal *animal = [[Animal alloc] init];        

        return animal;    

    }    

    return [super forwardingTargetForSelector:aSelector];

}

3、完整的消息转发

经历了前两步,还是无法处理消息,那么就会做最后的尝试,先调用methodSignatureForSelector:获取方法签名,然后再调用forwardInvocation:进行处理,这一步的处理可以直接转发给其它对象,即和第二步的效果等效,但是很少有人这么干,因为消息处理越靠后,就表示处理消息的成本越大,性能的开销就越大。所以,在这种方式下,会改变消息内容,比如增加参数,改变选择子等等。

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

- (void)forwardInvocation:(NSInvocation *)anInvocation

下面是改变选择子的例子

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {         NSLog(@"%@", NSStringFromSelector(aSelector));    

    if (aSelector == @selector(run)) {        

        NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:"];        

        return signature;    

    }    

    return [super methodSignatureForSelector:aSelector];

}

- (void)forwardInvocation:(NSInvocation *)anInvocation {    

    NSLog(@"%@", anInvocation);    

    NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:"];         anInvocation = [NSInvocation invocationWithMethodSignature:signature];    

    [anInvocation setSelector:@selector(runNew)];    

        if ([self respondsToSelector:@selector(runNew)]) {        

        [anInvocation invokeWithTarget:self];        

        return;    

    } else {        

        Animal *s = [[Animal alloc] init];        

       if ([s respondsToSelector:anInvocation.selector]) {            

            [anInvocation invokeWithTarget:s];            

            return;        

        }    

    }    

    [super forwardInvocation:anInvocation];

}

- (void)runNew {    

    NSLog(@"runNewrunNewrunNew");

}

你可能感兴趣的:(【iOS】消息转发机制)