swift类方法为什么使用表派发?

直接上答案:因为表派发允许子类重写父类的方法,并在运行时根据对象的实际类型调用正确的方法实现。

什么是表派发?

首先我们先知道的是,swift当中函数的派发机制主要分为静态派发和动态派发。动态派发又分为表派发和消息派发。

静态派发(直接派发)

静态派发的速度非常快,因为编译器能在编译时定位指令所在的位置(编译时就会绑定方法)。因此函数被调用时候,编译器直接跳转到函数的内存地址来执行操作。所以就会非常快。使用静态派发的主要是所有的值类型,扩展的方法,以及用final,static的修饰的类和属性。(由于stuct和enum是值类型,且不支持继承,所以编译器把方法放在静态派发)

扩展的方法为什么也是静态派发?

这里我们首先要明白扩展的本质:扩展的用途是为现的类型添加新的功能,而不修改原有类型的定义。

·扩展的方法在编译期间就会被静态的绑定到类型本身

·扩展不能参与类型的继承链

·扩展没有动态和多态,不能覆盖原有类型或字类中的方法。

扩展(extension)不会额外增加运行时的存储空间,因为扩展的本质是在编译期对类型的功能进行静态增强,而不是动态地向类型添加新成员(存储属性会改变类型的内存布局,而扩展被设计为一种编译时功能增强机制。如果允许扩展添加存储属性,会导致类型的内存布局不确定,影响已有代码的兼容性)。扩展是对类型的附加行为,扩展方法不参与类的继承体系,因此不能支持动态派发(多态)。

表(table)派送

表派送只要是利用一个表,该表是一组函数指针,成为witness table(虚拟表),实际上就是swift的运行时表,用来查找特定方法的实现。

witness如何工作的呢?

·每个子类都有自己对于此表的拷贝

·对于此类重写的每个方法,此表都有不同的函数指针

·对于子类添加新方法时,这些方法指针将附加到数组的结尾。

·最后编译器在表中查看为方法调用的具体实现

由于编译器必须从表中读取方法实现的内存地址,然后跳转地址,由于要执行两条指令,所以他比静态派发要慢,但比Message要快。使用表派发的主要是类的实例方法和子类可重写的方法。

消息(Message)派发

消息派发是一种动态派发机制,通过运行时的消息传递来调用方法。他不是直接调用方法的内存地址,而是把消息发送给对象,由对象动态解析方法。在swift中,消息派发主要是支持OC的动态特性,例如方法替换等(Method Swizzing)和运行时(runtime)消息解析。主要用于@objc和dynamic的方法。

回到最开始的为什么要使用表派发?主要是因为支持class的继承和方法的重写(多态),因为这些需要根据对象的实际类型来调用方法。静态派发的话,对象的动态类型无法在编译期间确定。

相关推荐
Dingdangr6 小时前
iOS中的类型推断及其在Swift编程语言中的作用和优势
开发语言·ios·swift
davidson147114 小时前
http网络服务-swift-Alamofire
网络协议·http·swift
Victor_Barnett2 天前
Xcode模拟器运行报错:The request was denied by service delegate
ide·macos·ios·objective-c·xcode·swift
波儿菜2 天前
Swift 减少指令数量的编码 Tips
swift
AntDreamer3 天前
苹果iPhone 17系列手机最新爆料,涉及五大方面更新
ios·智能手机·iphone·swift
zhangferry3 天前
iOS摸鱼周报 第三十六期
开发语言·ios·swift
AI生成曾小健3 天前
swift 命令行参数
开发语言·ios·swift
Swift社区3 天前
Swift 周报 第三十四期
ios·swift
Swift社区3 天前
Swift AsyncSequence — 代码实例详解
开发语言·ios·swift