依照类型区分
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派发
;