Swift 5.0的Runtime机制浅析
下面的图形展示了Swift中带@objc关键字的方法实现,以及OC语言调用Swift对象方法的实现: Swift类方法的运行时替换实现的可行性 从上面的介绍中我们已经了解到了Swift类的常规方法定义和调用实现的机制,同样了解到Swift对象实例的开头部分也有和OC类似的isa数据,用来指向类的信息结构。一个令人高兴的事情就是Swift类的结构定义部分是存放在可读写的数据段中,这似乎给了我们一个提示是说可以在运行时通过修改一个Swift类的虚函数表的内容来达到运行时对象行为改变的能力。要实现这种机制有三个难点需要解决: 一个是Swift对内存和指针的操作进行了极大的封装,同时Swift中也不再支持简单直接的对内存进行操作的机制了。这样就使得我们很难像OC那样直接修改类结构的内存信息来进行运行时的更新处理,因为Swift不再公开运行时的相关接口了。虽然可以将方法函数名称赋值给某个变量,但是这个变量的值并非是类方法函数的真实地址,而是一个包装函数的地址。 第二个就是Swift中的类方法调用和参数传递的ABI规则和其他语言不一致。在OC类的对象方法中,对象是作为方法函数的第一个参数传递的。在机器指令层面以arm64体系结构为例,对象是保存在x0寄存器作为参数进行传递。而在Swift的对象方法中这个规则变为对象不再作为第一个参数传递了,而是统一改为通过寄存器x20来进行传递。需要明确的是这个规则不会针对普通的Swift函数。因此当我们想将一个普通的函数来替换类定义的对象方法实现时就几乎变得不太可能了,除非借助一些OC到Swift的桥的技术和跳板技术来实现这个功能也许能够成功。 当然我们也可以通过为类定义一个extension方法,然后将这个extension方法函数的指针来替换掉虚函数表中类的某个原始方法的函数指针地址,这样能够解决对象作为参数传递的寄存器的问题。但是这里仍然需要面临两个问题:一是如何获取得到extension中的方法函数的地址,二是在替换完成后如何能在合适的时机调用原始的方法。 第三是Swift语言将不再支持内嵌汇编代码了,所以我们很难在Swift中通过汇编来写一些跳板程序了。 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |