依照类型区分
Value Type
像struct、enum这样的值类型,不支持继承,所以无需动态派发,它所有的办法调用,包括遵从的协议办法,都是直接调用;
值类型的函数、引证类型的函数且函数修饰词为final、extention中完成的办法(无法被重写)都归于直接派发;
在SIL(Swift Intermediate Language)中function_ref指令用于生成值类型函数的引证。
Class Type
关于一个纯 Swift class 来说,默许运用 Table 派发,影响它办法调用的关键字有final、dynamic和extension。
函数假如被标记成final,编译器就会知道这个办法不会被 override,并把它的调用办法标记成直接调用。而关于未标记成final并在 class 内部(非 extension)中定义的办法,Swift 会用一种叫作 Virtual Table 的机制来在运行时查找到这个办法并进行调用。
当一个办法被标记为dymanic,你有必要一起把它标记上@objc,此刻这个办法会运用 Message派发。
NSObject Subclass
影响这种类型的函数调用办法的关键字和上面相同,但是表现却不彻底相同。
标记为final和dynamic的函数可以参阅上面的 class。
在原生声明(非 extension)中定义的一般办法和标记为 @objc 的办法都运用 V-Table 机制派发。@objc 仅仅把办法暴露给 Objective-C,并没有改变办法派发的本质。
Extension 中的办法是直接派发的,但标记为 @objc 的函数需要对 Objc runtime 可见,就变成了 Message 派发。而且加不加dynamic生成的底层代码是相同的,这儿怀疑是编译器隐式的加上了dynamic关键字。
函数表派发
引证类型中,未经 final/dynamic修饰,且并不是在extension中完成的办法、protocol中的办法,都是运用函数表派发
SIL 运用class_method指令去获取应用类型中VTable中的办法进行调用,
运用 witness_method 指令获取protocol类型在WTable中的办法进行调用
Message派发
增加 @objc dynamic修饰的办法、或者NSObject子类中extension里的@objc办法,会运用Message派发;
只增加@objc,并不会修改动态派发,仅仅生成了oc和swift可见版本的办法
在SIL中运用objc_method指令进行法的调用。
依据Type类型区分音讯派发办法
| 目标/派发办法 | 静态派发 | VTable | WTable | 音讯(动态)派发 |
|---|---|---|---|---|
| Value Type | 默许行为 | 无 | :protocol | 无 |
| Swift Class | final、extension | 默许行为 | :protocol | dynamic |
| NSObject | final、extension | 默许行为 | :protocol | dynamic |
| protocol | extension | 默许行为 | 无 | :NSObjectProtocol @objc |
留意:Witness Table 仅在调用目标类型为 Protocol 类型时,才会被引证。
依据声明所在位置区分
| 原始位置 | extension | |
|---|---|---|
| Value Type | static | static |
| Class Type | V-Table | static |
| NSObject Subclass | V-Table | @objc为Message,其他为Static |
| protocol | N/A | static |
派发办法总结
-
Struct的办法默许是Static派发; -
Extension内的办法默许是Static派发; -
Swift Class和NSObject子类内部的办法,默许是V-Table派发; - 实例类型是
Protocol的类,调用protocol办法,是W-Table派发(留意实例类型有必要转换为Protocol); -
Protocol的默许完成即Protocol在Extension中的办法,默许是Static派发; -
final修饰的办法,是Static派发; -
@objc dynamic修饰办法,会变为Message派发; -
NSObject子类的Extension办法,运用@objc修饰,会变为Message派发;
