美文网首页
runtime中的消息转发

runtime中的消息转发

作者: guoguojianshu | 来源:发表于2019-05-04 19:38 被阅读0次

    1动态方法解析

    如果一个对象调用了在这个类中方法列表中找不到选择子(SEL),这个时候可以使用为这个选择子添加一个方法

    #import "ViewController.h"
    #import <objc/runtime.h>
    #import <objc/message.h>
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    void noParameterMethod (id self , SEL sel);
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        [self performSelector:@selector(method:) withObject:@"123"];
        [self performSelector:@selector(noParameterMethod)];
    }
    
    void method (id self ,SEL sel ,id objc){
        NSLog(@"%@",objc);
    }
    void noParameterMethod (id self , SEL sel){
        NSLog(@"无参数的函数");
    }
    
    +(BOOL)resolveInstanceMethod:(SEL)sel{
        NSLog(@"%@",NSStringFromSelector(sel));
        if ([NSStringFromSelector(sel) hasPrefix:@"method"]) {
            class_addMethod(self, sel, (IMP)method, "v@:@");
            return YES;
        }else if ([NSStringFromSelector(sel) hasPrefix:@"noParameterMethod"]){
            class_addMethod(self, sel, (IMP)noParameterMethod, "v@:");
            return YES;
        }else{
            return [super resolveInstanceMethod:sel];
        }
    }
    
    @end
    
    打印信息为

    备援接受者

    可以把自己不能识别的选择子交给其他对象进行处理

     [self performSelector:@selector(forwardSelecter)];
    -(id)forwardingTargetForSelector:(SEL)aSelector{
       NSString * selectorString =  NSStringFromSelector(aSelector);
        if ([selectorString isEqualToString:@"forwardSelecter"]) {
            SecondViewController * vc = [[SecondViewController alloc]init];
            return vc;
        }else{
            return [super forwardingTargetForSelector:aSelector];
        }
    }
    
    
    #import "SecondViewController.h"
    
    @interface SecondViewController ()
    
    @end
    
    @implementation SecondViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    }
    
    -(void)forwardSelecter{
        NSLog(@"备源消息转发");
    }
    

    完整的消息转发

      [self performSelector:@selector(normalForwardSelector)];
        [self performSelector:@selector(normalForwardPaSelector:) withObject:@"带有参数456"];
    
    -(void)forwardInvocation:(NSInvocation *)anInvocation{
        SEL sel =  anInvocation.selector;
        
        SecondViewController * vc = [[SecondViewController alloc]init];
        if ([vc respondsToSelector:sel]) {
            [anInvocation invokeWithTarget:vc];
        }else{
            [self doesNotRecognizeSelector:sel];
        }
    }
    
    -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
     NSMethodSignature * signature =   [super methodSignatureForSelector:aSelector];
        if (!signature) {
            signature = [NSMethodSignature signatureWithObjCTypes:"v@:"];
        }
        return signature;
    }
    
    
    #import "SecondViewController.h"
    
    @interface SecondViewController ()
    
    @end
    
    @implementation SecondViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    }
    
    -(void)forwardSelecter{
        NSLog(@"备源消息转发");
    }
    -(void)normalForwardSelector{
        NSLog(@"完整的消息转发");
    }
    -(void)normalForwardPaSelector:(NSString *)objc{
        NSLog(@"%@",objc);
    }
    @end
    

    Objective-C 中给一个对象发送消息会经过以下几个步骤:

    在对象类的 dispatch table 中尝试找到该消息。如果找到了,跳到相应的函数IMP去执行实现代码;

    如果没有找到,Runtime 会发送 +resolveInstanceMethod: 或者 +resolveClassMethod: 尝试去 resolve 这个消息;

    如果 resolve 方法返回 NO,Runtime 就发送-forwardingTargetForSelector: 允许你把这个消息转发给另一个对象;

    如果没有新的目标对象返回, Runtime 就会发送-methodSignatureForSelector:-forwardInvocation:消息。你可以发送 -invokeWithTarget:消息来手动转发消息或者发送 -doesNotRecognizeSelector: 抛出异常。

    相关文章

      网友评论

          本文标题:runtime中的消息转发

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