Runtime
注意啦:我写给自己看的,请不要打击我写简书的热情🤝。
Runtime的特性主要是消息(方法)传递,如果消息(方法)在对象中找不到,就进行转发。
1.啥叫Runtime
Objective-C 扩展了 C 语言,并加入了面向对象特性和消息传递机制。而这个扩展的核心是一个用 C 和 编译语言 写的 Runtime 库。它是 Objective-C 面向对象和动态机制的基石。
Objective-C 是一个动态语言,这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。理解 Objective-C 的 Runtime 机制可以帮我们更好的了解这个语言,适当的时候还能对语言进行扩展,从系统层面解决项目中的一些设计或技术问题。了解 Runtime ,要先了解它的核心 - 消息传递 。
Runtime 基本是用 C 和汇编写的,可见苹果为了动态系统的高效而作出的努力。苹果和GNU各自维护一个开源的 runtime 版本,这两个版本之间都在努力的保持一致。
高级编程语言想要成为可执行文件需要先编译为汇编语言再汇编为机器语言,机器语言也是计算机能够识别的唯一语言。
但是OC并不能直接编译为汇编语言,而是要先转写为纯C语言再进行编译和汇编的操作,从OC到C语言的过度就是由runtime来实现的。
对象(object),类(class)源码
2.消息传递
objec_msgSend的方法定义如下:OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)
OC调用方法[objc foo]的步骤
obj的根据isa指针找到它的 class-->在 class 的 方法列表(objc_method_list) 找 foo-->如果 class 中没到 foo,继续往它的 superclass 中找 -->一旦找到 foo 这个函数,就去执行它的实现IMP(一个函数指针,保存了方法的地址)。
但这种实现有个问题,效率低。因为一个class往往只有20%的函数会被经常调用,可能占总调用次数的80%。每个消息都需要遍历一次objc_method_list并不合理。
如果把经常被调用的函数缓存下来,那可以大大提高函数查询的效率。
objc_class中另一个重要成员objc_cache就是做这件事的
OC调用方法[objc foo]中,当找到foo之后,把foo的method_name作为key,method_imp作为value给存起来。
当OC再次调用方法[objc foo]的时候,可以直接在objc_cache里找到,避免去遍历objc_method_list。从前面的源代码可以看到objc_cache是存在objc_class结构体中的。
那消息传递是怎么实现的呢?
1.系统首先找到消息的接收对象,然后通过对象的isa找到它的类。
2.在它的类中查找method_list,是否有selector方法。
3.没有则查找父类的method_list。
4.找到对应的method,执行它的IMP。
5.转发IMP的return值。
3.消息传递用到的一些概念
1.类对象(objc_class)
Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。
typedef structobjc_class *Class;
实例(objc_object)
元类(Meta Class)
Method(objc_method)
SEL(objc_selector)
IMP
类缓存(objc_cache)
Category(objc_category)