Swift 示例代码中的方法调用采用哪种方法派发机制?
Swift协议方法派发机制问题解析
你给出的示例中,aaaa.printSome()调用采用静态派发,不会经过协议witness table完成方法寻址,最终执行AAA类中的实现,输出结果为B。
核心逻辑说明:
- 派发方式的判断核心首先看调用方的静态类型:示例中
aaaa通过AAA()直接初始化,没有做协议类型的向上转型,编译阶段编译器就能100%确定该实例的静态类型为具体类AAA,因此会直接将方法调用静态绑定到AAA内部实现的printSome(),不需要运行时查表。 - 你之前对静态派发的认知存在偏差:静态派发并非仅适用于方法只有单一实现的场景,只要编译阶段编译器能唯一确定调用目标的实现地址,就会采用静态派发,和方法存在多少个重写/默认实现没有直接关系。
- witness table的触发有明确前提:只有当调用方的静态类型是协议类型(即把实例作为
BBBB类型持有)时,对协议本身明确声明的方法的调用才会走witness table动态派发。举个对比例子:
如果let b: BBBB = AAA() b.printSome() // 此时才会通过witness table查找实现,最终同样输出BprintSome()没有写在BBBB的协议声明里,仅定义在协议扩展中,那么哪怕AAA实现了同名方法,以BBBB类型持有实例调用时,也会静态绑定到协议扩展的默认实现输出A,不会走witness table。 - 你查到的“扩展中的方法采用静态派发”的结论是准确的:类扩展中新增的方法、协议扩展中提供的方法默认都是静态派发;只有协议本体声明的必需方法,在调用方为协议类型时,才会通过witness table完成动态派发。
原问题示例代码:
protocol BBBB { func printSome() } extension BBBB { func printSome() { print("A") } } class AAA { } extension AAA: BBBB { func printSome() { print("B") } } let aaaa = AAA() aaaa.printSome()
内容的提问来源于stack exchange,提问作者Pyrettt Pyrettt
相关产品推荐
相关产品推荐

