那天和群里一我的聊天,他去过头条京东面试,用的 Swift,问的问题我都没都听过,其中就有这个 Swift 派发机制。决定仍是看下这些基础原理,而后忽然想到一个问题,为何要写博客呢,如今的想法是和别人交流的时候能逻辑很清晰的解释什么是 派发机制,否则以个人惯性,可能时间过一点就说的迷迷糊糊了。看了几篇文章,这两篇说得不错。git
kemchenj.github.io/2016-12-25-…github
www.jianshu.com/p/cfe7da018…swift
下面文章写的有点怪,是先带着结果看问题的。由于这也是我最开始的思路,和其余博客不太同样,我并非先遇到问题。这个话题是我想了解因此就直接查的问题,得出结论,而后根据结论分析一些代码例子,最后一步是提供验证这些结论是否正确的方法,由于最后一步比较乏味。ide
经过阅读上面两篇文章和 SIL 代码验证事后,swift 有四种派发方式:函数
第一篇文章中关于这个部分说的比较详细,大段抄过来不太好。。优化
派发机制总结表(我没验证全,用 SIL 验证了部分,剩余是看上面的文章的)ui
图中那个问好是我实践的和其余文章说的不同,最下面有说spa
除上图外的重要点:翻译
根据以上逻辑,有两个代码问题,刚看的时候有点疑惑,如今能够用上面的东西解释下
protocol MyProtocol {}
extension MyProtocol {
func testFuncA() {
print("protocol - funcA")
}
}
class Myclass: MyProtocol {
func testFuncA() {
print("class - funcA")
}
}
let x: MyProtocol = Myclass()
x.testFuncA() // protocol - funcA
复制代码
因为 x 是协议类型,因此先会去查协议的函数表,而协议里并无 funcA 的声明,因此协议函数表里就不存在这个方法,也不会去根据表查找实现,就走了协议的 extension 的直接派发。
protocol MyProtocol {
func testFuncA()
}
... (和上面同样)
let x: MyProtocol = Myclass()
x.testFuncA() // class - funcA
复制代码
因为协议函数表里声明了 funcA,因此用协议函数表查找实现,找到了在 Myclass 中的实现,走的函数表派发。
第三个问题 是上述文章提到的 SR-103
protocol Greetable {
func sayHi()
}
extension Greetable {
func sayHi() {
print("Hello")
}
}
class Person: Greetable {}
class LoudPerson: Person {
func sayHi() {
print("HELLO")
}
}
let x: Greetable = LoudPerson()
x.sayHi() // Hello,protocol
复制代码
这个被肯定是一个bug。按照正常的理解,协议函数表会查找子类的 sayhi 实现,可是实际上只找了遵循协议的那个 person 类,找不到,因此就走了协议 extension 的直接派发。可是三年过去了,这个bug好像并没被修复。。
Swift Intermediate Language(SIL) 是 Swift 在编译过程当中的中间产物。如今把这个文件解析成 SIL,上面第二个文章也说了方法,这里补充说明下吧。
swiftc -emit-silgen xxx.swift -Onone > xxxx.sil
struct TestStruct {
func testFunc1() { print("ss") }
}
let t = TestStruct()
t.testFunc1()
复制代码
以下图所示,咱们要分析的是 main 中的代码,经过搜寻函数名关键字能够看到 %9 那里是 function_ref
,能够看出这个是直接派发
如何看是不是派发方式:
function_ref
:直接派发class_method
:虚函数表派发witness_method
:证据表派发(不知道咋翻译了)objc_method
:消息机制派发