Swift派发的目的是让CPU知道被调用的函数在哪里,Swift语言支持编译型语言的直接派发,函数表派发,消息机制派发这三种派发机制.
- 1.直接派发
- 直接派发是最快的,原因是调用指令少,并且可以通过编译器进行比如内联等方式的优化,缺点是由于缺少动态性而不支持继承.
- 2.函数表派发
- 函数表派发具有动态性,在Swift里函数表叫 Witness Table,在其他语言中函数表叫 Virtual Table. 一个类里会用数组来存储里面的函数指针,override父类的函数会替代以前的函数,子类添加的函数会被加到这个数组里.
- 一个函数被调用时会先去读取对象的函数表,再根据类的地址加上该函数的偏移量得到函数地址,然后跳转到相应的地址上去,从编译后的字节码来看就是两次读取一次跳转,比直接派发慢.
- 3.消息机制派发
- 消息机制派发是指在运行时可以改变函数的行为,KVO和CoreData都是对这种机制的运用.OC默认使用的是消息机制派发,C语言使用的是直接派发,所以C语言派发性能高.Swift可以通过dynamic修饰来支持消息机制派发.
- 当一个消息被派发,程序运行时就会按照继承关系向上查找被调用的函数.但是这样做的效率不高,所以需要通过缓存来提高效率.这样查找性能就和函数表派发差不多了.
- 派发的使用场景
- 根据不同的使用场景,选择不同的派发方式.
- 值类型使用的是直接派发; class和协议的extension使用的是直接派发
- class和协议的初始化声明使用的是函数表派发;
- class的@object extension使用的是消息机制派发;
- 派发方式相关关键字
- final: 让类里的函数使用直接派发,这样该函数就没有动态性,程序运行时也无法取到这个函数
- dynamic: 可以让类里的函数使用消息机制派发,可以重载extension里的函数.