美文网首页
消息转发机制

消息转发机制

作者: CharmecarWang | 来源:发表于2018-11-22 14:58 被阅读0次

    在OC方法调用过程当中,当无法响应一个selector时,会触发消息转发机制。
    在触发消息转发机制之前,Runtime提供了两个轻量的方法来处理这个selector

    resolveInstanceMethod

    该方法主要是当前类为无法响应的selector提供方法实现(IMP)的机会。

    void dynamicMethodIMP(id self, SEL _cmd){/*...implementation...*/}
    + (BOOL) resolveInstanceMethod:(SEL)aSEL
    {
        if (aSEL == @selector(resolveThisMethodDynamically))
        {
              class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
              return YES;
        }
        return [super resolveInstanceMethod:aSel];
    }
    
    

    如果该selector是类方法,则使用resolveClassMethod

    如果resolveInstanceMethod返回NO,则说明该类无法为这个selector提供方法实现,此时将会调用forwordingTargetForSelector

    forwordingTargetForSelector

    这个方法简单的将selector转发给其他对象来处理。

    -(id)forwardingTargetForSelector:(SEL)aSelector{
        if (aSelector == @selector(dynamicSelector) && [self.myObj respondsToSelector:@selector(dynamicSelector)]) {
            return self.myObj;
        }else{
            return [super forwardingTargetForSelector:aSelector];
        }
    }
    
    

    forwardInvocation

    如果上面两个方法都无法处理这个selector,则会触发消息转发机制

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    

    methodSignatureForSelector尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。如果能获取,则返回非nil:创建一个 NSlnvocation 并传给forwardInvocation:。
    NSMethodSignature用来表示方法的签名信息:返回值,参数数量和类型。
    NSInvocation包含完整的消息,SEL + 执行SEL的Target + 参数值
    forwardInvocation我们可以做以下事情:

    • 修改SEL的名字
    • 修改执行SEL的Target
    • 修改参数

    如果forwardInvocation还不能处理这个selector,就会直接调用doesNotRecognizeSelector抛出异常。

    下面是改变选择子的例子,比如我们直接调用的是playPiano方法,最后转发给了traval:方法:

    // 完整的消息转发
    - (void)travel:(NSString*)city
    {
        NSLog(@"Teacher travel:%@", city);
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
        NSString *method = NSStringFromSelector(aSelector);
        if ([@"playPiano" isEqualToString:method]) {
            
            NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
            return signature;
        }
        return nil;
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
        SEL sel = @selector(travel:);
        NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
        anInvocation = [NSInvocation invocationWithMethodSignature:signature];
        [anInvocation setTarget:self];
        [anInvocation setSelector:@selector(travel:)];
        NSString *city = @"北京";
        // 消息的第一个参数是self,第二个参数是选择子,所以"北京"是第三个参数
        [anInvocation setArgument:&city atIndex:2];
        
        if ([self respondsToSelector:sel]) {
            [anInvocation invokeWithTarget:self];
            return;
        } else {
            Student *s = [[Student alloc] init];
            if ([s respondsToSelector:sel]) {
                [anInvocation invokeWithTarget:s];
                return;
            }
        }
        
        // 从继承树中查找
        [super forwardInvocation:anInvocation];
    }
    

    相关文章

      网友评论

          本文标题:消息转发机制

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