方法派發是一種用於選擇需要在呼叫時調用的適當方法的演算法。方法派發的主要目標是為程式提供有關在記憶體中可以找到特定方法的可執行程式碼的資訊。
編譯語言有三種類型的方法派發:
靜態派發是 Swift 中最快的派發方法。由於沒有方法覆寫可用,因此方法只有一個實現,並且它位於記憶體中的單一位置。
\ 我們可以使用關鍵字如 static、final、private 來使用靜態派發。
\ 靜態派發是值類型的預設方法派發,因為值類型不能被覆寫。
\ 讓我們看一些例子:
一旦我們將 final 關鍵字添加到類別中,其方法就不支援覆寫,這時靜態派發就會發揮作用。
// MARK: Final class final class ClassExample { // MARK: Static dispatch func method() { // implementation ... } }
一旦你使用擴展添加協議的預設實現,其派發方法就會切換到靜態派發,而不是使用見證表。
// MARK: Prorocol Extension extension ProtocolExample { // MARK: Direct Dispatch func method() { // implementation ... } } class ClassExample2: ProtocolExample {} let classExample2 = ClassExample2() classExample2.method()
當方法在擴展中實現時,這意味著它不能被子類覆寫。在這種情況下,有靜態派發的空間。
// MARK: Example Class Extension class ClassExample3 {} extension ClassExample3 { // MARK: Direct Dispatch func method() { // implementation ... } } let classExample3 = ClassExample3() classExample3.method()
我們不能在類別主體外訪問私有方法。這意味著該方法不能被覆寫並使用靜態派發。
// MARK: Access Control class ClassExample4 { // MARK: Direct Dispatch private func method() { // implementation ... } }
當我們必須處理繼承時,會使用表格派發。這是 Swift 中使用的預設派發類型。
對於類別或子類的每個實例,都會創建一個虛擬表,其中包含有關每個類別已實現方法的資訊,並存儲對適當實現的引用。虛擬表派發的主要缺點是它的速度比靜態派發慢。
\ 讓我們看一個例子:
// MARK: Virtual Table class ParentClass { func method1() {} func methdod2() {} } class ChildClass: ParentClass { override func method1() {} func method3() {} }
\ 對於每個實例,都會創建自己的虛擬表,如下所示:
\
見證表由協議使用,並為符合協議的每個類別創建。CPU 使用此表來確定應該在哪裡尋找適當的實現。符合協議的每種類型(值和引用)都有自己的協議見證表,其中包含指向協議所需的類型方法的指針。
\ 讓我們看一個例子:
// MARK: Witness Table Dispatch protocol ProtocolExample { func method1() func method2() } class ClassExample1: ProtocolExample { func method1() {} func method2() {} } class ClassExample2: ProtocolExample { func method1() {} func method2() {} }
\ 在這種情況下,為每個類別創建一個見證表:
\
訊息派發是最動態的方法派發風格。它在運行時尋找適當的實現。因為它在運行時操作,我們可以使用方法交換來更改方法實現。
\ 如果你想使用訊息派發,你需要在方法實現前添加 @objc dynamic。
// MARK: Message Dispatch class ClassExample: NSObject { @objc dynamic func method() {} } class SubClassExample: ClassExample { @objc dynamic override func method() {} } let subclass = SubClassExample() subclass.method()
\ 方法的實現在 SubClassExample 中搜尋。如果該類中沒有此方法的實現,則搜尋會在父類中繼續,依此類推,直到達到 NSObject。
\
讓我們將所有類型合併到一個表格中:
\
總結來說,Swift 中的方法派發是程式碼執行的關鍵方面,影響性能和靈活性。通過選擇正確的派發方法,開發人員可以優化他們的程式碼,確保適應性,並有效地利用 Swift 的動態功能。理解和掌握方法派發對於構建高效且適應性強的 Swift 應用程式至關重要。


