前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS_Swift函数派发机制

iOS_Swift函数派发机制

作者头像
mikimo
发布2023-10-18 14:54:40
2380
发布2023-10-18 14:54:40
举报
文章被收录于专栏:iOS开发~iOS开发~
前言:

函数调用机制是程序判断使用哪种途径去调用一个函数的机制,即 CPU 在内存中找到该函数地址并调用的过程。

了解函数的调用机制,对于写出高性能代码来说十分有必要。

1.Swift 函数派发类型

派发效率从高到底: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:

  • final 修饰的 和 extension 的函数:不可被继承和重写,所以都是静态派发。
  • 其他的函数:以 Table 的机制来查找调用的。

2.3 Class - Extension

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

2.4 NSObject Subclass

  • final 修饰的函数:同 Class
  • dynamic 修饰的 和 extension 的 函数:通过 objc_msgSend 方式派发

以上都是在没有编译器优化的情况下的派发方式,在有优化的情况下,编译器会尽可能地将方法变成静态派发 ,有的方法甚至会就地展开,变成 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 指定编译器进行内敛优化。

使用建议:

  • 默认:编译器自己决定要不要使用 inline 进行优化
  • @inline(never):永远不要使用内敛优化。函数特别长且不想增大包体积时使用。
  • @inline(__always):重视使用内敛优化。函数很小且希望提高效率时使用(其实编译器也会做相应的优化,所以这样声明也不会提高速度)。

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方法调用

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 1.Swift 函数派发类型
    • 1.1 static dispatch
      • 1.2 table dispatch
        • 1.3 objc_msgSend
        • 2.派发类型识别
          • 2.1 Struct / Enum
            • 2.2 Class
              • 2.3 Class - Extension
                • 2.4 NSObject Subclass
                  • 2.5 Protocol 对象
                    • 2.6 修饰符
                      • 2.6.1 @objc/@nonobjc:
                      • 2.6.2 dynamic:
                      • 2.6.3 @inline:
                  • 3.总结
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档