美文网首页
runtime之消息转发机制

runtime之消息转发机制

作者: hallfrita | 来源:发表于2018-01-11 16:54 被阅读0次

    在程序中,调用我们未实现或找不到的方法时,程序就会崩溃,如下

    Person *person = [Person new];
    
    //    [person run];
    
    [person performSelector:@selector(run)];
    

    调用person类的run方法时,会报下面错


    图1.png

    其实,抛异常前,这个消息经过了三件事,我们重写这几个方法,就能很好的改变这些方法的实现,实现消息转发

    1、动态添加方法:尝试动态给目标类(比如这个例子为Person)添加一个方法来实现这个未知的selector。

    2、消息转发重定向:尝试寻找另一个能够识别该selector的receiver。

    3、标准的消息转发:对消息使用NSInvocation对象进行重新包装,给receiver最后一次识别机会。

    示意图如下

    图2.png

    一、动态添加方法 resolveInstanceMethod

    我们这里用newRun这个方法替换这个未实现的run

    + (BOOL)resolveInstanceMethod:(SEL)sel {
    
        NSLog(@"sel = %@", NSStringFromSelector(sel));
    
        // 1、动态添加方法
    
        if (sel == @selector(run)) {
    
            class_addMethod(self, sel, (IMP)newRun, "v@:v");
    
            return YES;
    
        }
    
        return [super resolveInstanceMethod:sel];
    
    }
    

    newRun方法

    void newRun(id self,SEL sel, NSString *str) {
    
        NSLog(@"--------run is implement %@--------", str);
    
    }
    

    二、 消息重定向forwardingTarget

    这里将Person的run方法重定向到Animation的run实现

    - (id)forwardingTargetForSelector:(SEL)aSelector {
    
        NSLog(@"%@",NSStringFromSelector(aSelector));
    
        // 2、消息转发重定向
    
        if ([NSStringFromSelector(aSelector) isEqualToString:@"run"]) {
    
            return [Animation new];
    
        } else {
    
            return [super forwardingTargetForSelector:aSelector];
    
        }
    
    }
    

    三、标准的消息转发 forwardInvocation

      // 3、生成方法签名
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
        NSString *sel = NSStringFromSelector(aSelector);
    
        if ([sel isEqualToString:@"run"]) {
    
            return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    
        } else {
    
            return [super methodSignatureForSelector:aSelector];
    
        }
    
    }
    
    // 4、拿到方法签名配发消息
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
    
        NSLog(@"-----%@",anInvocation);
    
        SEL seletor = [anInvocation selector];
    
        Animation *anim = [Animation new];
    
        if ([anim respondsToSelector:seletor]) {
    
            [anInvocation invokeWithTarget:anim];
    
        } else {
    
            [super forwardInvocation:anInvocation];
    
        }
    
    }
    

    最后,如果跑了这几个方法都没有找到,我么还可以给一个友好的提示

    // 5、抛出友好异常
     - (void)doesNotRecognizeSelector:(SEL)aSelector {
         NSString *selStr = NSStringFromSelector(aSelector);
         NSLog(@"%@ dose not recognize.......",selStr);
     }
    

    相关文章

      网友评论

          本文标题:runtime之消息转发机制

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