当前位置: 首页 > article >正文

Swift的方法派发机制

1. 静态派发(Static Dispatch)

静态派发在编译时确定方法的具体实现,调用时直接跳转到该实现。静态派发的优点是性能高,因为不需要运行时查找方法实现。

适用场景:
  • 值类型(Struct 和 Enum):值类型的方法默认使用静态派发。

  • Final 类和方法:标记为 final 的类或方法无法被继承或重写,因此使用静态派发。

  • 全局函数和静态方法:这些方法在编译时就能确定实现,使用静态派发。

示例:
struct Point {
    var x: Int
    var y: Int
    
    func 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 代码。


http://www.kler.cn/a/542510.html

相关文章:

  • (五)C++的类继承、多态、组合
  • IDEA接入DeepSeek
  • 第三届通信网络与机器学习国际学术会议(CNML 2025)
  • 【hive】记一次hiveserver内存溢出排查,线程池未正确关闭导致
  • Java 中 ArrayList 和 LinkedList 有什么区别?
  • Android Studio超级详细讲解下载、安装配置教程(建议收藏)
  • 模块化的基本概念
  • docker 安装 Prometheus、Node Exporter 和 Grafana
  • 【如何掌握CSP-J 信奥赛中的排序算法】
  • oracle执行grant授权sql被阻塞问题处理
  • 【PromptCoder + Bolt.new】自动生成页面和路由——提升开发效率的利器
  • 简述C#多线程
  • Zookeeper 作注册中心 和nacos 和eruka 有什么差异 ?基于什么理论选择?
  • 第七节 文件与流
  • spring cloud 使用 webSocket
  • SpringCloud - Gateway 网关
  • 常用电路(过压保护、电流/电压采集)
  • 开源AI智能名片2+1链动模式S2B2C商城小程序在实体店与线上营销中的应用探索
  • 教程 | MySQL 基本指令指南(附MySQL软件包)
  • 最新PHP盲盒商城系统源码 晒图+免签+短信验证+在线回收 ThinkPHP框架
  • MySQL——CRUD
  • Java爬虫:高效获取1688商品详情的“数字猎人”
  • 林语堂 | 生活的智慧在于逐渐澄清滤除那些不重要的杂质,而保留最重要的部分
  • AH比价格策略源代码
  • HALCON 数据结构
  • Vision Transformer:打破CNN垄断,全局注意力机制重塑计算机视觉范式