美文网首页runtime&runloop
iOS面试--Runtime(动态运行时)

iOS面试--Runtime(动态运行时)

作者: 唐师兄 | 来源:发表于2020-02-26 14:24 被阅读0次

    前言

    2020年已经注定了:新型冠状病毒肆虐,追了 15 年的偶像Kobe与世长辞,禽流感来袭等等。这是多灾多难的一年! 太多的坏事情坏消息消耗了人们太多的热情和信心,我们只能将一切寄予希望,即使是很空虚的希望;我们憧憬新型冠状病毒的离开,生活重归于好,我们期待时间能够治愈科比离世带给我们的痛苦,所有的这些坏事情坏消息仅仅是一个开始,它们还没有开足马力,由于惯性,还会横冲直撞一段时间和路程。 过苦日子的悲惨现实,已经支撑不起伟大、强大和辉煌的梦想。所以我们只能寄希望于未来,而为了我们的未来,所以还是要继续前行!!!
    Dear thoughts are in my mind, and my soul it soars enchanted.

    矫情之后,还是要回归正题。关于 Runtime 的面试,我们主要从下面几个问题出发。

    • 编译时语言和 Objective-C 这种动态运行时语言有何区别?
    • 消息传递和函数调用有什么不同?
    • 当我们调用一个方法没有实现时,系统是如何为我们转发?
    • 当我们在消息传递的过程中,如何进行方法缓存的查找?

    Runtime

    runtime 概述

    runtime 我们主要是从以下八个模块去分析,数据结构、类对象与元类对象、消息传递、方法缓存、方法转发、Method-Swizzling、动态添加方法以及动态方法解析,如下图所示


    runtime 数据结构

    objc_object

    objc_object 其实就是 id,每一个 objc_object 中均有一个 isa 指针

    objc_object 数据结构
    • isa_t 指针
    • 关于 isa 操作
    • 弱引用相关
    • 关联对象相关方法
    • 内存管理相关方法


      id 内部结构体
    Class == objc_class
    objc_class
    • isa 指针
    • 共用体 isa_t


      isa 指针

      其实在 32 位架构的机器上,那么 isa 指针的位数就是 32 位,64 位机器则为 64 位。如图所示以 64 位为例,isa指针包括指针型 isa 指针和非指针型 isa 指针,指针型的 isa 的值代表的就是 class 的地址,对于非指针型的 isa,那么 isa 的部分值代表 class 的地址,为什么会这样设计,因为有时候 class 的地址的长度不需要那么长,那么多余的位数可以用来存储其他的值。

    isa 指向

    • 关于对象的 isa 指针,其指向的是类对象
    • 对于实例对象来说(id),isa 指针指向的是其 Class 对象;
    • 关于类对象(Class),其 isa 指针指向的是其元类对象(meta_class)
    cache_t

    主要用于提高方法调用的速度或者消息传递的速度

    • 用于\color{red}{快速查找}方法执行函数
    • 是一个\color{red}{可增量扩展}的哈希表结构 (用哈希主要是提高查找效率)
    • \color{red}{局部性原理}的最佳应用
      局部性原理:把调用方法频率最高的放到缓存中以提高命中率
      cache_t 数据结构

    class_data_bits_t

    • class_data_bits_t 主要是对 class_rw_t 的封装
    • class_rw_t 代表的是类相关的读写信息、对 class_ro_t 的封装
    • class_ro_t 代表的是类的只读信息

    class_rw_t

    class_rw_t 的数据结构
    class_rw_t 原理解析

    https://www.jianshu.com/p/585845127007

    class_ro_t

    class_ro_t 数据结构

    method_t

    函数四要素:函数的名称、函数的返回值、函数的参数、函数体


    method_t 数据结构

    如上图所示

    • name:方法的名称
    • types:函数的返回值和参数的组合
    • imp: 无类型的函数指针,指向的就是函数体

    \color{red}{types 是如何表述函数的返回值和参数?}

    Type Encodings runtime 数据结构表

    对象、类对象、元类对象

    • 类对象存储实例方法列表等信息
    • 元类对象存储类对象的方法列表等信息
    对象、类对象、元类对象之间的关系图

    如上图所示,实例对象可以通过 isa 指针找到其类对象,而类对象可以通过 isa 指针找到他的元类对象;同时类对象可以通过 superclass 指针找到它的 Superclass 对象一直到 Rootclass,元类对象也是如此;类对象和元类对象因为继承自 NSObject, 所以他们中也有 isa 指针,对于每一个元类对象的 isa 指针都指向根元类对象;根元类对象的 superclass指针指向的是根类对象

    消息传递

    消息传递流程图

    缓存查找

    类对象查找(已排序的列表采用二分查找、未排序的使用一般遍历)
    元类对象查找(父类逐级遍历)

    消息转发流程

    消息转发流程
    https://www.jianshu.com/p/ba0e9942a082

    Method Swizzling

    动态添加一个方法?

    当面试官问你@dynamic关键字的时候,如何回答?

    • 动态运行时语言将函数的决议推迟到运行时
    • 编译时语言在编译期间进行函数的决议

    runtime 实际面试问题

    1. [obj foo] 和 objc_msgsend()函数之间有什么关系?
     objc_msgSend()是[obj foo]的具体实现。
     在runtime中,objc_msgSend()是一个c函数,[obj foo]会被翻译成这样的形式objc_msgSend(obj, foo)。
    系统会先去obj的对应的类中找方法;
    再进行缓存,找不到再去找方法列表;
    再找父类,如此逐级向上传递;
    最后再找不到就要转发。
    
    2. runtime 如何通过Selector 找到对应的 IMP 地址的?(考察消息传递机制)
    对于实例方法,每个实例的 isa 指针指向着对应类对象,
    而每一个类对象中都一个对象方法列表。
    对于类方法,每个类对象的 isa 指针都指向着对应的元对象,
    而每一个元对象中都有一个类方法列表。
    方法列表中记录着方法的名称,方法实现,以及参数类型,
    其实 selector 本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现。
    Selector、Method 和 IMP 的关系可以这样描述:在运行时分发消息,方法列表中的每一个实体都是一个方法(Method),
    它的名字叫做选择器(SEL),对应着一种方法实现(IMP)。
    
    3. 能否向编译后的类中添加实例变量?
    4. 能否向运行时动态创建的类中添加实例变量?为什么?

    相关文章

      网友评论

        本文标题:iOS面试--Runtime(动态运行时)

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