依照类型区分

Value Type

像struct、enum这样的值类型,不支持继承,所以无需动态派发,它所有的办法调用,包括遵从的协议办法,都是直接调用

值类型的函数、引证类型的函数且函数修饰词为final、extention中完成的办法(无法被重写)都归于直接派发

在SIL(Swift Intermediate Language)中function_ref指令用于生成值类型函数的引证。

Class Type

关于一个纯 Swift class 来说,默许运用 Table 派发,影响它办法调用的关键字有finaldynamicextension

函数假如被标记成final,编译器就会知道这个办法不会被 override,并把它的调用办法标记成直接调用。而关于未标记成final并在 class 内部(非 extension)中定义的办法,Swift 会用一种叫作 Virtual Table 的机制来在运行时查找到这个办法并进行调用。

当一个办法被标记为dymanic,你有必要一起把它标记上@objc,此刻这个办法会运用 Message派发。

NSObject Subclass

影响这种类型的函数调用办法的关键字和上面相同,但是表现却不彻底相同。

标记为finaldynamic的函数可以参阅上面的 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 ClassNSObject子类内部的办法,默许是V-Table派发;
  • 实例类型是Protocol的类,调用protocol办法,是W-Table派发留意实例类型有必要转换为Protocol);
  • Protocol的默许完成即Protocol在Extension中的办法,默许是Static派发
  • final修饰的办法,是Static派发
  • @objc dynamic修饰办法,会变为Message派发
  • NSObject子类的Extension办法,运用@objc修饰,会变为Message派发