Runtime

作者: rebeccaBull | 来源:发表于2019-08-24 20:30 被阅读0次
    我的理解Runtime就是:
    1)、一套用C/C++和汇编实现的一套API
    OC就是运行时机制,其中最主要的是消息机制。
    对于C语言,函数的调用在编译的时候会决定调用哪个函数;
    对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。
    2)、OC 是一个全动态语言,OC 的一切都是基于 Runtime 实现的
    平时编写的OC代码, 在程序运行过程中, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者
    举例:
    [[Person alloc] init]
    runtime :
    objc_msgSend(objc_msgSend("Person" , "alloc"), "init")
    
    一、数据结构:
    objc_object,objc_class,isa,class_data_bits_t,cache_t,method_t
    objc_object(id)
          isa_t:关于isa操作相关,弱引用相关,关联对象相关,内存管理相关
    objc_class (class) :继承自objc_object
    isa指向:
          关于对象,其指向类对象。
          关于类对象,其指向元类对象。
          实例--(isa)-->class--(isa)-->MetaClass
    cache_t:用于快速查找方法执行函数,是可增量扩展的哈希表结构,是局部性原理的最佳运用
    method_t:
      函数四要素:名称,返回值,参数,函数体
      struct method_t {
          SEL name;           //名称
          const char *types;//返回值和参数
          IMP imp;              //函数体
       }
    
    二、对象,类对象,元类对象
    类对象存储实例方法列表等信息。
    元类对象存储类方法列表等信息。
    
    三、消息传递的流程:(如何通过selector找到对应的IMP地址)
    缓存查找-->当前类查找-->父类逐级查找
    1.调用方法之前,先去查找缓存,看看缓存中是否有对应选择器的方法实现,如果有,就去调用函数,完成消息传递(缓存查找:给定值SEL,目标是查找对应bucket_t中的IMP,哈希查找)
    2.如果缓存中没有,会根据当前实例的isa指针查找当前类对象的方法列表,看看是否有同样名称的方法 ,如果找到,就去调用函数,完成消息传递(当前类中查找:对于已排序好的方法列表,采用二分查找,对于没有排序好的列表,采用一般遍历)
    3.如果当前类对象的方法列表没有,就会逐级父类方法列表中查找,如果找到,就去调用函数,完成消息传递(父类逐级查找:先判断父类是否为nil,为nil则结束,否则就继续进行缓存查找-->当前类查找-->父类逐级查找的流程)
    4.如果一直查到根类依然没有查找到,则进入到消息转发流程中,完成消息传递
    
    举例:
    下面以实例对象调用方法[blackDog walk]为例描述方法调用的流程
    1)、编译器会把`[blackDog walk]`转化为`objc_msgSend(blackDog,SEL)`,SEL为@selector(walk)。
    2)、Runtime会在blackDog对象所对应的Dog类的方法缓存列表里查找方法的SEL
    3)、如果没有找到,则在Dog类的方法分发表查找方法的SEL。(类由对象isa指针指向,方法分发表即methodList)
    4)、如果没有找到,则在其父类(设Dog类的父类为Animal类)的方法分发表里查找方法的SEL(父类由类的superClass指向)
    5)、如果没有找到,则沿继承体系继续下去,最终到达NSObject类。
    6)、如果在234的其中一步中找到,则定位了方法实现的入口,执行具体实现
    7)、如果最后还是没有找到,会面临两种情况:``(1) 如果是使用`[blackDog walk]`的方式调用方法````(2) 使用`[blackDog performSelector:@selector(walk)]`的方式调用方法
    
    四、消息转发:
    1)、动态方法解析
    接收到未知消息时(假设blackDog的walk方法尚未实现),runtime会调用+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方法)
    2)、备用接收者
    如果以上方法没有做处理,runtime会调用- (id)forwardingTargetForSelector:(SEL)aSelector方法。
    如果该方法返回了一个非nil(也不能是self)的对象,而且该对象实现了这个方法,那么这个对象就成了消息的接收者,消息就被分发到该对象。
    适用情况:通常在对象内部使用,让内部的另外一个对象处理消息,在外面看起来就像是该对象处理了消息。
    比如:blackDog让女朋友whiteDog来接收这个消息
    3)、完整消息转发
    在- (void)forwardInvocation:(NSInvocation *)anInvocation方法中选择转发消息的对象,其中anInvocation对象封装了未知消息的所有细节,并保留调用结果发送到原始调用者。
    比如:blackDog将消息完整转发給主人dogOwner来处理
    

    五、应用

    1、发送消息
    方法调用的本质,就是让对象发送消息。
    objc_msgSend,只有对象才能发送消息,因此以objc开头.
    使用消息机制前提,必须导入#import <objc/message.h>
    2、交换方法
    3、类\对象的关联对象
    4、动态添加方法
    5、字典转模型KVC实现
    

    相关文章

      网友评论

        本文标题:Runtime

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