派发效率从高到底:Static dispatch > Table dispatch > Message dispatch

1.1 static dispatch

Static dispatch 静态派发,即直接地址调用。这个函数指针编译链接完成后就确定了,存放代码段
优点:派发速度最快,因为需要调用指令集少,且编译器还有很大的优化空间(如:函数内敛 inline)。
缺点:局限也是最大的,因为缺乏动态性,所以没法支持继承

1.2 table dispatch

Table dispatch 函数表派发,是编译型语言实现动态行为常见实现方式函数使用一个数组存储声明每个函数指针。大部分语言把这个称之为 Virtual Table函数表,Swift 里称为 Witness Table
每个类维护一个函数表,记录着类的所有函数。如果被 override 的话,表里只会保存 override 后的函数。子类新增函数会被插到这个数组的最后没有位置可以extension 安全插入函数。
优点:可扩展
缺点:速度慢编译器对某些含有副作用的函数无法优化

1.3 objc_msgSend

基于 Objc RunTime 实现,沿着实例isa 指针进行查找,找不到最后还有3次拯救机会。详细可见:iOS_Objective-C 消息发送(消息查找 及 消息转发)过程
优点:最动态的方式可以实现 KVO、UIAppearance 和 CoreData 等功能。可在运行时改变函数行为。不只可以通过 swizzling 来改变,甚至可以isa-swizzling 修改对象继承关系可以面向对象基础上实现自定义派发
确定:速度最慢


2.派发类型识别

2.1 Struct / Enum

StructEnum 为值类型,不支持继承,它不需要一个 Table 来记录方法信息。所以它的方法调用(包括协议方法),都是静态派发的。

2.2 Class

对于一个 pure swift class

2.3 Class – Extension

extension 中的方法属性无法继承重写,只属于当前类,所以是静态派发的。

2.4 NSObject Subclass

以上都是在没有编译器优化的情况下的派发方式,在有优化的情况下,编译器会尽可能地将方法变成静态派发 ,有的方法甚至会就地展开,变成 inline 的形式,以便提升性能

2.5 Protocol 对象

无论真实对象是值类型还是引用类型,都使用 Table dispatch


2.6 修饰符

2.6.1 @objc/@nonobjc

@objc/@nonobjc 只是修改objc 的可见性,并不会更改其派发方式。默认依旧是 Table dispatch
@objc:是将是 swift 中 继承自 NSObject 类的函数暴露给 OC。原理生成两个函数引用一个swift 调用,一个给 objc 调用。
@nonobjc隐藏对 objc 的可见性,依然使用 Table dispatch

2.6.2 dynamic

dynamic 强制使用消息派发,可以动态修改。
修饰属性实现 KVO,否则 setter 会走直接派发,无法触发 KVO。

2.6.3 @inline

@inline 指定编译器行内优化

使用建议


3.总结

struct / Enum Class NSObject Subclass
只要有final Static Static
Extension Static Static Static
Extension + @objc / dynamic Static Static msgSend
默认 Static Table Table
@objc Table Table
@objc dynamic msgSend msgSend
Protocol Static Table Table

Reference:
Understanding Swift Performance
Optimizing Swift Performance
Swift 中的方法调用(Method Dispatch)(一) – 概述
Swift方法调用
Swift方法调用

原文地址:https://blog.csdn.net/Margaret_MO/article/details/130048750

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_24374.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注