iOS面试题(三)--Runtime相关

150 阅读3分钟

1.Runtime数据结构相关

1.1 objc_object

Objective-C的面向对象都是基于C/C++的数据结构——结构体实现的。 我们平时使用的所有对象都是id类型,id类型对象对应到runtime中,就是objc_object结构体。

image.png

1.2 objc_class

Class指针用来指向一个 Objective-C 的类,它是objc_class结构体类型,所以class、meta-class底层结构都是objc_class结构体,objc_class继承自objc_object,所以它也有isa指针,它也是对象。

objc_class包含三个成员变量:superClasss指向当前类的父类,cache_t是用来提供消息传递过程中的缓存方法查找,class_data_bits_t是类的基本信息,如成员变量、属性、方法列表,包括通过分类所添加的成员、属性、 方法。

image.png

1.3 isa指针

isa指针用来维护对象和类之间的关系,并确保对象和类能够通过isa指针找到对应的方法、实例变量、属性、协议等。

它有指针型isa和非指针型的isa.指针型isa的值代表Class地址,非指针型isa值的部分代表Classs地址。 image.png

isa指向?

image.png

1.4 cache_t 是一个装满了bucket_t的Hash表。

用于快速查找方法执行函数;是可增量扩展的哈希表结构;是局部性原理的最佳应用。

image.png

1.5 class_data_bits_t

class_data_bits_t主要是对class_rw_t的封装

class_rw_t代表了类相关的读写信息、对class_ro_t的封装

image.png

class_ro_t代表了类相关的只读信息

image.png

1.6 method_t

Method就是method_t类型的指针。

method_t是对方法/函数的封装(函数四要素:函数名、返回值、参数、函数体)

image.png

Type Encodings

image.png

1.7 整体数据结构图 image.png

2.类对象与元类对象&消息传递相关

2.1 类对象和元类对象是什么?

类对象是存储实例方法列表等信息,元类对象存储类方法列表等信息。

image.png

2.2 打印出来的都是 Phone?

self class 转化成objc_msgSend方法,指的是当前对象。 super class 转化成objc_msgSendSupper方法,super里面包的receiver,也是当前对象,所以打印出来都是Phone。

image.png

2.2消息传递

image.png

image.png

消息传递过程:缓存是否命中? 当前类方法列表是否命中? 逐级父类方法列表是否命中? image.png

3.方法缓存查找相关

3.1方法缓存查找的流程步骤?

根据给定的方法选择器SEL,通过哈希查找对应bucket_t中的方法实现IMP。

3.2 当前类中查找

对于已排序好的列表,采用二分查找算法查找方法对应执行函数。

对于没有排序的列表,采用一般遍历查找方法对应执行函数。

3.3 父类逐级查找

image.png

4.消息转发相关

4.1 消息转发流程是什么样的? image.png

image.png

5.Method-Swizzling相关

image.png

6.动态添加方法相关

6.1 你是否使用过perforSelector:方法?

image.png

7.动态方法解析相关

7.1 是否使用过@dynamic 属性? 当我们用@dynamic修饰时,代表不需要编译器在编译时生成getter和settre方法的具体实现,而是在运行时具体的调用的时候再去为他添加具体实现。

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

8.Runtime实战

8.1 [obj foo]和objc_msgSend()函数之间有什么关系?

编译器的处理过后,[obj foo]就转化成obj_msgSend()函数调用了,就开始了消息传递的过程。

8.2 runtime如何通过Selector找到对应的IMP地址的?

首先查找当前实例所对应类对象的缓存是否有selector的IMP实现,如果缓存命中就把缓存的函数返回给调用方,如果缓存没有命中,再根据当前类的方法列表去查找对应selector的IMP实现,当前类如果没有命中,再根据当前类的superClass指针逐级查找父类的方法列表。然后查找selector的IMP实现。

8.3 能否向编译后的类中增加实例变量?

不能,编译之前已经完成了实例变量的布局,class_ro_t ,readOnly,即编译后没有办法修改的。 如果是动态添加的类中,可以增加实例变量。