美文网首页
【iOS】消息转发机制

【iOS】消息转发机制

作者: Colin_狂奔的蚂蚁 | 来源:发表于2018-04-02 17:21 被阅读68次
    消息转发机制图

    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】消息转发机制

          本文链接:https://www.haomeiwen.com/subject/iquxhftx.html