1. 靜態派發(Static Dispatch)
靜態派發在編譯時確定方法的具體實現,調用時直接跳轉到該實現。靜態派發的優點是性能高,因為不需要運行時查找方法實現。
適用場景:
-
值類型(Struct 和 Enum):值類型的方法默認使用靜態派發。
-
Final 類和方法:標記為?
final
?的類或方法無法被繼承或重寫,因此使用靜態派發。 -
全局函數和靜態方法:這些方法在編譯時就能確定實現,使用靜態派發。
示例:
struct Point {var x: Intvar y: Intfunc description() -> String {return "(\(x), \(y))"}
}let p = Point(x: 10, y: 20)
print(p.description()) // 靜態派發
2. 動態派發(Dynamic Dispatch)
動態派發在運行時確定方法的具體實現。Swift 中的動態派發主要通過虛表(VTable)和消息轉發(Message Forwarding)實現。
2.1 虛表派發(VTable Dispatch)
虛表派發是類方法默認的派發方式。每個類都有一個虛表,其中存儲了該類所有可重寫方法的指針。子類繼承父類的虛表,并可以覆蓋其中的方法指針。
適用場景:
-
類的非 Final 方法:類的方法默認使用虛表派發,除非標記為?
final
。 -
繼承和重寫:子類可以重寫父類的方法,運行時根據對象的實際類型調用正確的方法。
示例:
class Animal {func makeSound() {print("Some sound")}
}class Dog: Animal {override func makeSound() {print("Bark")}
}let animal: Animal = Dog()
animal.makeSound() // 動態派發,輸出 "Bark"
2.2 消息轉發(Message Forwarding)
消息轉發是 Objective-C 的派發機制,Swift 通過?@objc
?和?dynamic
?關鍵字支持這種派發方式。消息轉發允許在運行時動態解析方法調用,甚至可以在運行時修改方法實現。
適用場景:
-
與 Objective-C 交互:標記為?
@objc
?的方法使用消息轉發。 -
動態方法解析:標記為?
dynamic
?的方法使用消息轉發,允許在運行時修改方法實現。
示例:
class MyClass {@objc dynamic func sayHello() {print("Hello")}
}let instance = MyClass()
instance.sayHello() // 消息轉發
3. 協議派發(Protocol Witness Table Dispatch)
協議方法使用協議見證表(Protocol Witness Table, PWT)進行派發。每個遵循協議的類型都有一個 PWT,其中存儲了協議方法的實現指針。
適用場景:
-
協議方法:協議中的方法默認使用 PWT 派發。
-
泛型約束:泛型類型約束為協議時,使用 PWT 派發。
示例:
protocol Greetable {func greet()
}struct Person: Greetable {func greet() {print("Hello")}
}let greeter: Greetable = Person()
greeter.greet() // 協議派發
4. 特殊場景
4.1 泛型方法派發
泛型方法在編譯時生成特定類型的實現,通常使用靜態派發。但如果泛型類型約束為協議,則使用協議派發。
示例:
func printGreeting<T: Greetable>(_ greeter: T) {greeter.greet() // 協議派發
}let person = Person()
printGreeting(person) // 輸出 "Hello"
4.2 擴展中的方法派發
擴展中的方法默認使用靜態派發,即使是對類類型的擴展。如果擴展中的方法被重寫,仍然使用靜態派發。
示例:
class MyClass {func sayHello() {print("Hello from MyClass")}
}extension MyClass {func sayGoodbye() {print("Goodbye from MyClass")}
}class SubClass: MyClass {override func sayHello() {print("Hello from SubClass")}// 無法重寫擴展中的方法
}let instance: MyClass = SubClass()
instance.sayHello() // 動態派發,輸出 "Hello from SubClass"
instance.sayGoodbye() // 靜態派發,輸出 "Goodbye from MyClass"
4.3?@objc
?和?dynamic
?方法
標記為?@objc
?的方法使用消息轉發,允許與 Objective-C 交互。標記為?dynamic
?的方法也使用消息轉發,允許在運行時修改方法實現。
示例:
class MyClass {@objc dynamic func sayHello() {print("Hello")}
}let instance = MyClass()
instance.sayHello() // 消息轉發
4.4?final
?關鍵字
標記為?final
?的類或方法無法被繼承或重寫,因此使用靜態派發。
示例:
final class MyFinalClass {func sayHello() {print("Hello")}
}let instance = MyFinalClass()
instance.sayHello() // 靜態派發
總結
Swift 的方法派發機制靈活且高效,支持多種派發方式以適應不同的場景:
-
靜態派發:適用于值類型、Final 類和方法,性能最高。
-
動態派發:適用于類的繼承和重寫,通過虛表派發。
-
協議派發:適用于協議方法,通過協議見證表派發。
-
消息轉發:適用于與 Objective-C 交互和動態方法解析。
理解這些派發機制有助于編寫高效且符合預期的 Swift 代碼。