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

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

什么是表派发?

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

静态派发(直接派发)

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

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

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

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

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

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

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

表(table)派送

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

witness如何工作的呢?

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

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

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

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

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

消息(Message)派发

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

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

相关推荐
躺平每一天17 分钟前
用 Swift 的高阶函数 reduce 提升代码可读性
swift·掘金·金石计划
风浅月明3 天前
[Swift]pod install成功后运行项目报错问题error: Sandbox: bash(84760) deny(1)
swift
season_zhu3 天前
iOS开发:关于Moya之上的Request层
ios·架构·swift
东坡肘子3 天前
更短的有效期和更长的保质期 | 肘子的 Swift 周报 #080
swiftui·swift·wwdc
风浅月明4 天前
[Swift]Xcode模拟器无法请求http接口问题
http·xcode·swift
season_zhu7 天前
iOS开发:关于URL解析
ios·json·swift
ZRD11127 天前
SwiftUI 表达式
swiftui·swift
一牛8 天前
AppKit 中的响应者链
macos·objective-c·swift
WDeLiang9 天前
学习笔记 - Swfit 6.1 - 语法概览
笔记·学习·swift
胎粉仔9 天前
Swift —— delegate 设计模式
开发语言·设计模式·swift