zoukankan      html  css  js  c++  java
  • iOS 消息转发机制

    消息机制: 调用任何方法的时候 其实都相当于给这个对象发送一个消息

     

    举例 如下方法

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self test];
        // Do any additional setup after loading the view.
    }
    
    - (void)test{
        NSLog(@"%@",self); //<ViewController: 0x104e089b0>
        NSLog(@"%@",NSStringFromSelector(_cmd)); //test
    }
    
    @end

    每一个方法的调用其实默认都携带了两个参数 一个是 id 类型的self 一个是SEL 类型的_cmd 

    _cmd 其实是方法编号

    在发送这个消息的时候、系统会根据方法编号去方法缓存列表查询方法(汇编查询效率较高)

    如果缓存中未找到开启慢速查找 按照实例对象-> 类对象 -> 元类对象的顺序查找 (实例方法存在去类对象中、类方法存在于元类对象中) 如果找到就缓存起来

    如果没找到就会进入动态方法解析阶段 如下 Person 没有实现run 进入消息动态放解析阶段时、可以动态添加方法

    @interface Person : NSObject
    - (void)run;
    @end
    
    
    #import "Person.h"
    #import <objc/message.h>
    @implementation Person
    /*
       动态解析 对象方法
     */
    + (BOOL)resolveInstanceMethod:(SEL)sel {
        if (sel == @selector(run)) {
            class_addMethod(self, sel, (IMP)dynamicMethod, "v@:");
            return YES;
        }
        return [super resolveInstanceMethod:sel];
    }
    
    void dynamicMethod(){
        NSLog(@"%s",__func__);
    }
    @end

    如果还没没有找到则进入消息转发流程

     

    - (id)forwardingTargetForSelector:(SEL)aSelector{
        if (aSelector == @selector(run)) {
            return [[Cat alloc] init];
        }
        return [super forwardingTargetForSelector:aSelector];
    }
    /*
     如果没有实现forwardingTargetForSelector 就会调用下面的返回方法签名 如果返回了方法签名就会调用forwardInvocation  否则直接调用doesNotRecongnizeSelector
     */
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
        if (aSelector == @selector(run)) {
            return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        }
        return [super methodSignatureForSelector:aSelector];
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
        [anInvocation invokeWithTarget:[[Cat alloc] init]];
        NSLog(@"anInvocation");
    }
    
    void dynamicMethod(){
        NSLog(@"%s",__func__);
    }
    @end

     实际应用 利用消息转发机制 可以避免开发中的一些 unrecognized selector sent to崩溃

    @interface Cat : NSObject
    - (void)run;
    - (void)walk;
    @end
    
    
    #import "Cat.h"
    
    @implementation Cat
    - (void)run{
        NSLog(@"%s",__func__);
    }
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
        if ([self respondsToSelector:aSelector]) {
            return [super methodSignatureForSelector:aSelector];
        }
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    - (void)forwardInvocation:(NSInvocation *)anInvocation{
        NSLog(@"没有找到%@",NSStringFromSelector(anInvocation.selector));
    }
    @end
  • 相关阅读:
    C
    A
    G
    B
    一些新玩意:
    Angular常用功能
    node学习笔记(四)
    node学习笔记(三)
    node学习笔记(二)
    node学习笔记
  • 原文地址:https://www.cnblogs.com/ZhangShengjie/p/14707160.html
Copyright © 2011-2022 走看看