Swift-方法排程-類的普通方法底層探究

一眼萬年的星空發表於2021-10-31

1. 類的普通方法排程

寫一個結構體和一個類,對比看看方法呼叫的方式:

// 結構體
struct PersonStruct {
    func changClassName() {}
}

let s = PersonStruct()
s.changClassName()

// 類
class PersonClass {
    func changClassName() {}
}

let c = PersonClass()
c.changClassName()

 

生成 SIL 程式碼:

【1】結構體及類的 SIL 程式碼:

 

與結構體不同的是:為PersonClass類自動生成了一個反初始化方法。

【2】執行方法的 SIL 程式碼:

 

在呼叫的方式中,可以看到類的方法,不是由function_ref 修飾而是class_method修飾。

 

【3】還有一個不同點是,SIL 中為 PersonClass 自動生成了sil_vtable

 

由上面 SIL 程式碼,我們可以看出,SIL 為類的方法建立了 sil_vtable,並在呼叫時,用class_method來修飾。這樣的類的方法排程,是Swift 中動態派發的一種方式,叫做函式派發。

這裡sil_vtable 關鍵字宣告的就是函式表。 函式表初始化的原始碼如下:

 

從原始碼中看,函式表中的資料結構是一個陣列,原始碼是以遍歷的的方式去獲取函式表內的函式的,所以函式表是按順序存放類中可能是函式派發去執行的函式,但是不一定函式表內的函式都會被以函式派發的方式去排程。

2. OC 繼承鏈中的方法列表儲存結構

我們知道 OC 中的方法是訊息派發的方式。 每個物件中都有一個 isa 指標,指向自己的類。類中存放著該類實現的方法列表。本類方法列表中存放著本類實現的方法及父類方法列表的指標。在訊息派發時,會先查詢本來的方法列表,如果沒找到,再去查詢父類的方法列表,以此類推,來尋找方法的實現。

假設A類繼承B類,B類繼承C類,如下圖所示:

 

3. Swift 繼承連中的函式表儲存結構

Swift 類中數派發訊息派發類似, 所有類也會維護一個自己的函式表, 不同的是所有未被複寫的父類所實現的函式地址都會拷貝在這個表中, 而不是由一個指向父類方法表的指標替代, 被重寫的函式,在函式表中會指定為子類中的函式。由於少了一步指標定址步驟, 在派發效率上要比基於訊息的派發高效

假設A類繼承B類,B類繼承C類如下圖所示:

 

程式碼驗證一下:
Swift
 
 
class PersonClass: NSObject {
    override init() {
        super.init()
        @objc func changClassName7() {}
        dynamic func changClassName8() {}
    }
}

class PersonClassSub: PersonClass {
    func runSub() {}
    // 重寫的函式,在函式表中會指定為子類中的函式
    override func changClassName7() {}
}

class PersonClassSubSub: PersonClassSub {
    func runSubSub() {}
}

 

到這裡,證實2件事情:

  • Swift的函式表是按順序存放的
  • 在類的繼承關係中,函式表中存放所有的方法,由上到下,依次排列,先是父類的方法,再是子類的方法。

 

以上為這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家支援。

青山不改,綠水長流,後會有期,感謝每一位佳人的支援!

 

相關文章