当前位置:网站首页>Swift运行时(派发机制)
Swift运行时(派发机制)
2022-08-02 02:23:00 【~废弃回忆 �༄】
消息的三种派发机制
直接派发(Direct Dispatch)
- 直接派发是最快的,不止是因为需要调用的指令集会更少,并且编译器还能够有很大的优化空间,例如函数内联等,直接派发也有人称为静态调用。
- 然而,对于编程来说直接调用也是最大的局限,而且因为缺乏动态性所以没办法支持继承和多态。
函数表派发(Table Dispatch)
- 函数表派发是编译型语言实现动态行为最常见的实现方式函数表使用了一个数组来存储类声明的每一个函数的指针.大部分语言把这个称为virtual table"虚函数表), Swift里称为“witness table.每一个类都会维护一个函数表,里面记录着类所有的函数,如果父类函数被 override的话,表里面只会保存被 override之后的函数.一个子类新添加的函数,都会被插入到这个数组的最后运行时会根据这一个表去决定实际要被调用的函数
- 查表是一种简单,易实现,而且性能可预知的方式.然而,这种派发方式比起直接派发还是慢一点从字节码角度来看,多了两次读和一次跳转,由此带来了性能的损耗.另一个慢的原因在于编译器可能会由于函数内执行的任务导致无法优化(如果函数带有副作用的话)
- 这种基于数组的实现,缺陷在于函数表无法拓展.子类会在虚数函数表的最后插入新的函数,没有位置可以让 extension安全地插入函数.
消息机制派发(Message Dispatch)
- 消息机制是调用函数最动态的方式.也是Ccoa的基石,这样的机制催生了kvo, UIAppearence和 CoreData等功能.这种运作方式的关键在于开发者可以在运行时改变函数的行为.不止可以通过 swizzling来改变,甚至可以用 isa-swizzling修改对象的继承关系可以在面向对象的基础上实现自定义派发.
Swift运行时
- 纯 Swift类的函数调用已经不再是 Objective-c的行时发消息,而是类似C++的vtable,在编译时就确定了调用哪个函数,所以没法通过 runtime获取方法、属性。
- 而Swift为了兼容 Objective-C,凡是继承自 NSObjec的类都会保留其动态性,所以我们能通过 runtime拿到他的方法。这里有一点说明:老版本的 Swift(如2.2)是编译期隐式的自动帮你加上了@objc,而40以后版本的 Swift编译期去掉了隐式特性,必须使用显式添加。
- 不管是纯Swift类还是继承自 NSObject的类只要在属性和方法前面添加@objc关键字就可以使用 runtime.
| 项目 | 原始定义 | 扩展 |
|---|---|---|
| 值类型 | 直接派发 | 直接派发 |
| 协议 | 函数表派发 | 直接派发 |
| 类 | 函数表派发 | 直接派发 |
| 继承自NSObject的类 | 函数表派发 | 消息机制派发 |
小结
- 值类型总是会使用直接派发,简单易懂
- 而协议和类的 extension都会使用直接派发
- NSObject的 extension会使用消息机制进行派发
- NSObject声明作用域里的函数都会使用函数表进行派发.
- 协议里声明的,并且带有默认实现的函数会使用函数表进行派发
一些关键字的派发机制
| 关键字 | 机制 |
|---|---|
| final | 直接派发 |
| dynamic | 消息机制派发 |
| @objc & @nonobjc | 改变在OC里的可见性 |
| @inline | 告诉编译器可以直接派发 |
Swift 运行时-final @objc
- 可以在标记为 final的同时,也使用@objc让函数可以使用消息机制派发.这么做的结果就是,调用函数的时候会使用直接派发,但也会在 Objective-c的运行时里注册响应的 selector.函数可以响应 perform(selector)以及别的 Objective-C特性但在直接调用时又可以有直接派发的性能.
边栏推荐
- 项目场景 with ERRTYPE = cudaError CUDA failure 999 unknown error
- bool框架::PosInGrid (const简历:关键点kp, int &posX, int诗句)
- 2022河南青训联赛第(三)场
- leetcode / anagram in string - some permutation of s1 string is a substring of s2
- 永磁同步电机36问(二)——机械量与电物理量如何转化?
- 790. 数的三次方根
- Rasa 3.x 学习系列- Rasa - Issues 4873 dispatcher.utter_message 学习笔记
- IMU预积分的简单理解
- 优炫数据库导库导错了能恢复吗?
- Redis 底层的数据结构
猜你喜欢
随机推荐
789. 数的范围
【LeetCode每日一题】——704.二分查找
Hash collisions and consistent hashing
EFCore 反向工程
Garbage Collector CMS and G1
Scheduled tasks for distributed applications in Golang
Nanoprobes免疫测定丨FluoroNanogold试剂免疫染色方案
[ORB_SLAM2] void Frame::ComputeImageBounds(const cv::Mat & imLeft)
"NetEase Internship" Weekly Diary (3)
Nanoprobes纳米探针丨Nanogold偶联物的特点和应用
极大似然估计
How engineers treat open source
Golang分布式应用之Redis
Personal blog system project test
MySQL - CRUD operations
Entry name 'org/apache/commons/codec/language/bm/gen_approx_greeklatin.txt' collided
2022-08-01 Reflection
Rasa 3.x 学习系列- Rasa - Issues 4873 dispatcher.utter_message 学习笔记
nacos启动报错,已配置数据库,单机启动
欧拉公式的证明




![[Unity entry plan] 2D Game Kit: A preliminary understanding of the composition of 2D games](/img/8a/07ca69c6dcc22757156cb615e241f8.png)



