浅谈Swift派发机制

直接派发

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派发机制的资料请关注我们其它相关文章!

(0)

相关推荐

  • 分析Swift性能高效的原因

    自从2014年Apple发布Swift语言以来,历时六年多,Swift已经发布到5.3版本,在5.0版本已经ABI stability,5.2版本也已经module stability,不管是语言还是基础库都日趋稳定,目前国内外大厂也都积极拥抱Swift阵营. 绝大多数公司选择Swift语言开发iOS应用,主要原因是因为Swift相比Objc有更快的运行效率,更加安全的类型检测,更多现代语言的特性提升开发效率:这一系列的优点使Swift语言的热度越来越高. 大多数人知道Swift语言相比于Obj

  • swift中defer的实际应用小结

    看看苹果官方的介绍 用 defer 语句在即将离开当前代码块时执行一系列语句.该语句让你能执行一些必要的清理工作,不管是以何种方式离开当前代码块的--无论是由于抛出错误而离开,或是由于诸如 return.break 的语句.例如,你可以用 defer 语句来确保文件描述符得以关闭,以及手动分配的内存得以释放. defer 语句将代码的执行延迟到当前的作用域退出之前.该语句由 defer 关键字和要被延迟执行的语句组成.延迟执行的语句不能包含任何控制转移语句,例如 break.return 语句,

  • 详解Swift 结构体

    Swift 结构体是构建代码所用的一种通用且灵活的构造体. 我们可以为结构体定义属性(常量.变量)和添加方法,从而扩展结构体的功能. 与 C 和 Objective C 不同的是: 结构体不需要包含实现文件和接口. 结构体允许我们创建一个单一文件,且系统会自动生成面向其它代码的外部接口. 结构体总是通过被复制的方式在代码中传递,因此它的值是不可修改的. 语法 我们通过关键字 struct 来定义结构体: struct nameStruct { Definition 1 Definition 2

  • Swift UIButton使用教程

    一.UIButton基本操作 1.创建按钮 let btn: UIButton = UIButton()//没有样式 let btns:UIButton =UIButton(type: UIButtonType)//有样式 let button = UIButton(frame:CGRect(x:10, y:150, width:100, height:30))//简化创建方式 UIButtonType有以下类型 public enum UIButtonType : Int { case cus

  • Swift在什么情况会发生内存访问冲突详解

    前言 众所周知,Swift 是一门类型安全的语言,它会通过编译器报错来阻止你代码中不安全的行为.比如变量必须在使用之前声明.变量被销毁之后内存不能在访问.数组越界等问题. Swift 会通过对于修改同一块内存,同一时间以互斥访问权限的方式(同一时间,只能有一个写权限),来确保你的代码不会发生内存访问冲突.虽然 Swift 是自动管理内存的,在大多数情况下你并不需要关心这个.但理解何种情况下会发生内存访问冲突也是十分必要的. 首先,来看一下什么是内存访问冲突. 内存访问冲突 当你设值或者读取变量的

  • SwiftUI学习之state和Binding的区别浅析

    @state 绑定值的状态,其属性的修饰官方推荐使用private.上代码(ps:这里没用private 进行修饰,是为了演示区别) import SwiftUI struct FilterView: View { // @Binding var isFavorite: Bool @State var isFavorite = true var body: some View { Toggle(isOn: $isFavorite) { } let buttonTitle = isFavorite

  • Swift仿微信语音通话最小化时后的效果实例代码

    前言 最近碰到个需求,需要仿微信语音通话缩小化后,保持界面最上层有一个悬浮的小View可以一点击就把刚刚缩放掉的界面再放回来,其实本质就是创造了一个新的Window,在这个window上创建了一个rootController并展示他,缩小化时是把controller dismiss掉了,再次点击那个小View之后把这个controller再展示出来便可以了.同理微信小程序其实也是在一个新的Window中做了一套新的逻辑.随着现在手机性能的提升,多Window同时存在并不会造成严重卡顿,而衍生出来

  • SwiftUI 中创建反弹动画的实现

    SwiftUI 中的动画 在写动画之前呢先简单回顾一下 SwiftUI 中动画的几个要点: 动画是 view 发生变化时的渐变效果 SwiftUI 动画分为隐式动画( .animation() )与显式动画( withAnimation() )两种 隐式动画是给 view 加动画,view 所有的能动画的变化都能被隐式动画影响 显式动画是针对某个变化进行动画,能精准控制. view 的插入和移除通过过渡( transition )来做效果,可以组合多个过渡或自定义过渡 要构建自定义动画,我们需要

  • swift中正确安全声明一个单例的方法实例

    Talk is cheap. Show me the code. class TestShareInstance{ var age:Int static let shareInstane:TestShareInstance = TestShareInstance(age: 3); private init(age:Int){ self.age = age; }; } 说说原理 swift在类中,类变量是能够保证线程安全,swift底层,static关键字的实际上是使用dispatch_once语

  • 浅谈Swift派发机制

    直接派发 C++ 默认使用的是直接派发,加上 virtual 修饰符可以改成函数表派发.直接派发是最快的,原因是调用指令会少,还可以通过编译器进行比如内联等方式的优化.缺点是由于缺少动态性而不支持继承. struct DragonFirePosition { var x:Int64 var y:Int32 func land() {} } func DragonWillFire(_ position:DragonFirePosition) { position.land() } let posi

  • 浅谈oracle SCN机制

    SCN(System Change Number)作为oracle中的一个重要机制,在数据恢复.Data Guard.Streams复制.RAC节点间的同步等各个功能中起着重要作用.理解SCN的运作机制,可以帮助你更加深入地了解上述功能. 在理解SCN之前,我们先看下oracle事务中的数据变化是如何写入数据文件的: 1.事务开始: 2.在buffer cache中找到需要的数据块,如果没有找到,则从数据文件中载入buffer cache中: 3.事务修改buffer cache的数据块,该数据

  • 浅谈Java 代理机制

    目录 一.常规编码方式 二.代理模式概述 三.静态代理 3.1.什么是静态代理 3.2.代码示例 四.Java 字节码生成框架 五.什么是动态代理 六.JDK 动态代理机制 6.1.使用步骤 6.2.代码示例 七.CGLIB 动态代理机制 7.1.使用步骤 7.2.代码示例 八.什么情况下使用动态代理 九.静态代理和动态代理对比 十.总结 一.常规编码方式 在学习代理之前,先回顾以下我们的常规编码方式:所有 interface 类型的变量总是通过向上转型并指向某个实例的. 1)首先,定义一个接口

  • 浅谈Linux信号机制

    一.信号列表 root@ubuntu:# kill -l  1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP  6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20)

  • 浅谈Flink容错机制之作业执行和守护进程

    一.作业执行容错 Flink 的错误恢复机制分为多个级别,即 Execution 级别的 Failover 策略和 ExecutionGraph 级别的 Job Restart 策略.当出现错误时,Flink 会先尝试触发范围小的错误恢复机制,如果仍处理不了才会升级为更大范围的错误恢复机制,具体可以看下面的序列图. 当 Task 发生错误,TaskManager 会通过 RPC 通知 JobManager,后者将对应 Execution 的状态转为 failed 并触发 Failover 策略.

  • 浅谈Android IPC机制之Binder的工作机制

    进程和线程的关系 按照操作系统中的描述,线程是CPU调度的最小单位,同时线程也是一种有限的系统资源.而进程一般是指一个执行单元,在pc端或者移动端上是指一个程序或者一个应用.一个进程中可以包含一个或者是多个线程.所以他们的关系应该是包含和被包含的关系. 跨进程的种类 在Android中跨进程通信的方式有很多种,Bundle,文件共享,AIDL,Messenger,ContentProvider,Socket,这些都能实现进程间之间的通信,当然,虽然都能够实现进程间通信,但是他们之间的实现原理或者

  • 浅谈Java锁机制

    目录 1.悲观锁和乐观锁 2.悲观锁应用 3.乐观锁应用 4.CAS 5.手写一个自旋锁 1.悲观锁和乐观锁 我们可以将锁大体分为两类: 悲观锁 乐观锁 顾名思义,悲观锁总是假设最坏的情况,每次获取数据的时候都认为别的线程会修改,所以每次在拿数据的时候都会上锁,这样其它线程想要修改这个数据的时候都会被阻塞直到获取锁.比如MySQL数据库中的表锁.行锁.读锁.写锁等,Java中的synchronized和ReentrantLock等. 而乐观锁总是假设最好的情况,每次获取数据的时候都认为别的线程不

  • 浅谈Redis缓冲区机制

    目录 Redis缓冲区机制 客户端缓冲机制 应对输入缓冲区溢出 查看输入缓冲区信息 如何解决输入缓冲区溢出 应对输出缓冲区溢出 Monitor命令的执行 输出缓冲区设置不合理 主从集群中的缓冲区 复制缓冲区 复制缓冲区溢出 复制积压缓冲区 解决复制积压缓冲区溢出 Redis缓冲区机制 Redis中的缓冲区机制就是为了平衡客户端发送命令和服务端处理命令的速度差异,如果客户端写入过快或者服务端读取过慢这就会导致缓冲区溢出,缓冲区一旦溢出将引发一系列的性能问题,下面我们详细聊聊. 客户端缓冲机制 Re

  • 浅谈Java内省机制

    目录 概念 JavaBean 内省 相关API 代码案例:获取属性相关信息 内省属性的注意事项 完整代码 概念 JavaBean 在实际编程中,我们常常需要一些用来包装值对象的类,例如Student. Employee.Order,这些 类中往往没有业务方法,只是为了把需要处理的实体对象进行封装,有这样的特征: 属性都是私有的: 有无参的public构造方法: 对私有属性根据需要提供公有的getXxx方法以及setXxx方法: 比如:属性名称为name,则有getName方法返回属性name值,

  • 浅谈.NET反射机制的性能优化 附实例下载

    可能大家谈到反射面部肌肉都开始抽搐了吧!因为在托管语言里面,最臭名昭著的就是反射!它的性能实在是太低了,甚至在很多时候让我们无法忍受.不过不用那么纠结了,老陈今天就来分享一下如何来优化反射! 概述 本文涉及到的反射优化的途径有如下两种: 通过Delegate.CreateDelegate()创建委托进行优化 通过.NET4的动态运行时进行优化 如果您还知道其他更加有效的优化途径,请不吝赐教! 准备工作 今天我们总计要对比五种不同的调用对象成员的方式,也算是一种性能测评. 在开始之前,我们首先定义

随机推荐