浅谈swift派发机制-kb88凯时官网登录

来自:网络
时间:2023-07-25
阅读:
目录

直接派发

c 默认使用的是直接派发,加上 virtual 修饰符可以改成函数表派发。直接派发是最快的,原因是调用指令会少,还可以通过编译器进行比如内联等方式的优化。缺点是由于缺少动态性而不支持继承。

struct dragonfireposition {
var x:int64
var y:int32
func land() {}
}
 
func dragonwillfire(_ position:dragonfireposition) {
position.land()
}
let position = dragonfireposition(x: 342, y: 213)
dragonwillfire(position)

编译 inline 后 dragonwillfire(dragonfireposition(x: 342, y: 213)) 会直接跳到方法实现的地方,结果就变成 position.land()。

函数表派发

java 默认就是使用的函数表派发,通过 final 修饰符改成直接派发。函数表派发是有动态性的,在 swift 里函数表叫 witness table,大部分语言叫 virtual table。一个类里会用数组来存储里面的函数指针,override 父类的函数会替代以前的函数,子类添加的函数会被加到这个数组里。举个例子:

class fish {
func swim() {}
func eat() {
//normal eat
}
}
 
class flyingfish: fish {
override func eat() {
//flying fish eat
}
func fly() {}
}

编译器会给 fish 类和 flyingfish 类分别创建 witness table。在 fish 的函数表里有 swim 和 eat 函数,在 flyingfish 函数表里有父类 fish 的 swim,覆盖了父类的 eat 和新增加的函数 fly。

一个函数被调用时会先去读取对象的函数表,再根据类的地址加上该的函数的偏移量得到函数地址,然后跳到那个地址上去。从编译后的字节码这方面来看就是两次读取一次跳转,比直接派发还是慢了些。

消息机制派发

这种机制是在运行时可以改变函数的行为,kvo 和 coredata 都是这种机制的运用。oc 默认就是使用的消息机制派发,使用 c 来直接派发获取高性能。swift 可以通过 dynamic 修饰来支持消息机制派发。

当一个消息被派发,运行时就会按照继承关系向上查找被调用的函数。但是这样效率不高,所以需要通过缓存来提高效率,这样查找性能就能和函数派发差不多了。

具体派发

声明

值类型都会采用直接派发。无论是 class 还是协议 的 extension 也都是直接派发。class 和协议是函数表派发。

指定派发方式

  • final:让类里的函数使用直接派发,这样该函数将会没有动态性,运行时也没法取到这个函数。
  • dynamic:可以让类里的函数使用消息机制派发,可以让 extension 里的函数被 override。

派发优化

swift 会在这上面做优化,比如一个函数没有 override,swift 就可能会使用直接派发的方式,所以如果属性绑定了 kvo 它的 getter 和 setter 方法可能会被优化成直接派发而导致 kvo 的失效,所以记得加上 dynamic 的修饰来保证有效。后面 swift 应该会在这个优化上去做更多的处理。

以上就是浅谈swift派发机制的详细内容,更多关于swift派发机制的资料请关注其它相关文章!

返回顶部
顶部
网站地图