swift class的动态派发
一、测试代码
class BaseCallClass{
func NormalCall(){}
@objc func OcCall(){}
@objc dynamic func OcDynamicCall(){}
}
class DerivedCallClass:BaseCallClass{
override func NormalCall(){}
@objc override func OcCall(){}
@objc dynamic override func OcDynamicCall(){}
}
func FuncTest(object:BaseCallClass)
{
object.NormalCall()
object.OcCall()
object.OcDynamicCall()
}
func DoneTest(){
FuncTest(object: BaseCallClass())
FuncTest(object: DerivedCallClass())
}
二、命令行
swiftc -emit-sil DispatchCall.swift | xcrun swift-demangle > DispatchCall.silgen
cat DispatchCall.silgen
三、虚函数表
虚函数表中,函数的名称都以:基类+函数名称的形式定义;
同时映射到具体的函数;
sil_vtable BaseCallClass {
#BaseCallClass.NormalCall!1: (BaseCallClass) -> () -> () : @DispatchCall.BaseCallClass.NormalCall() -> () // BaseCallClass.NormalCall()
#BaseCallClass.OcCall!1: (BaseCallClass) -> () -> () : @DispatchCall.BaseCallClass.OcCall() -> () // BaseCallClass.OcCall()
}
sil_vtable DerivedCallClass {
#BaseCallClass.NormalCall!1: (BaseCallClass) -> () -> () : @DispatchCall.DerivedCallClass.NormalCall() -> () [override] // DerivedCallClass.NormalCall()
#BaseCallClass.OcCall!1: (BaseCallClass) -> () -> () : @DispatchCall.DerivedCallClass.OcCall() -> () [override] // DerivedCallClass.OcCall()
}
四、动态派发
1、调用代码:
// FuncTest(object:)
sil hidden @DispatchCall.FuncTest(object: DispatchCall.BaseCallClass) -> () : $@convention(thin) (@guaranteed BaseCallClass) -> () {
// %0 // users: %7, %6, %5, %4, %3, %2, %1
bb0(%0 : $BaseCallClass):
debug_value %0 : $BaseCallClass, let, name "object", argno 1 // id: %1
%2 = class_method %0 : $BaseCallClass, #BaseCallClass.NormalCall!1 : (BaseCallClass) -> () -> (), $@convention(method) (@guaranteed BaseCallClass) -> () // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed BaseCallClass) -> ()
%4 = class_method %0 : $BaseCallClass, #BaseCallClass.OcCall!1 : (BaseCallClass) -> () -> (), $@convention(method) (@guaranteed BaseCallClass) -> () // user: %5
%5 = apply %4(%0) : $@convention(method) (@guaranteed BaseCallClass) -> ()
%6 = objc_method %0 : $BaseCallClass, #BaseCallClass.OcDynamicCall!1.foreign : (BaseCallClass) -> () -> (), $@convention(objc_method) (BaseCallClass) -> () // user: %7
%7 = apply %6(%0) : $@convention(objc_method) (BaseCallClass) -> ()
%8 = tuple () // user: %9
return %8 : $() // id: %9
} // end sil function 'DispatchCall.FuncTest(object: DispatchCall.BaseCallClass) -> ()'
2、虚函数表中的函数派发:
通过class_method(类的实例变量、函数名称)的形式查找虚函数表到具体的函数;
然后apply执行;先将函数绑定到类实例,得到方法;然后调用方法执行;
3、oc的动态派发
sil提供了对swift方法的统一实现提供了两个实现:oc可见实现和swift具体功能实现;同时将oc可见实现构造进oc的派发列表中;
派发列表的搜索和oc原生的搜索一致;先搜索子类的实现,没有再搜索父类的实现;
提供给oc派发列表的函数是一个中间函数,这个函数与具体实现的函数一一对应,并实现了对具体函数的调用;
先通过objc_method(类的实例变量、函数名称)查找派发列表得到chunk函数;chunk函数与函数的具体实现一一对应;
然后调用chunk函数;
chunk函数内部调用函数的具体实现;
// DerivedCallClass.OcDynamicCall()
sil hidden @DispatchCall.DerivedCallClass.OcDynamicCall() -> () : $@convention(method) (@guaranteed DerivedCallClass) -> () {
// %0 // user: %1
bb0(%0 : $DerivedCallClass):
debug_value %0 : $DerivedCallClass, let, name "self", argno 1 // id: %1
%2 = tuple () // user: %3
return %2 : $() // id: %3
} // end sil function 'DispatchCall.DerivedCallClass.OcDynamicCall() -> ()'
// @objc DerivedCallClass.OcDynamicCall()
sil hidden [thunk] @@objc DispatchCall.DerivedCallClass.OcDynamicCall() -> () : $@convention(objc_method) (DerivedCallClass) -> () {
// %0 // users: %4, %3, %1
bb0(%0 : $DerivedCallClass):
strong_retain %0 : $DerivedCallClass // id: %1
// function_ref DerivedCallClass.OcDynamicCall()
%2 = function_ref @DispatchCall.DerivedCallClass.OcDynamicCall() -> () : $@convention(method) (@guaranteed DerivedCallClass) -> () // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed DerivedCallClass) -> () // user: %5
strong_release %0 : $DerivedCallClass // id: %4
return %3 : $() // id: %5
} // end sil function '@objc DispatchCall.DerivedCallClass.OcDynamicCall() -> ()'
五、第三方解释chunk:
chunk只是包壳,功能有二:1、oc继承体系中派发列表可见;2、消息转发给具体的实现;
The magic bit of glue here is a thunk. In the Swift to Objective-C world, this is an additional method callable from Objective-C. It’s a thin wrapper and all it needs to do is call through to the native Swift method.
https://swiftunboxed.com/interop/objc-dynamic/
swift class的动态派发的更多相关文章
- Swift 静态派发和动态派发
前言 方法是 Swift 中的一个重要概念,方法允许你把需要复用的代码封装进方法中,这样当你调用方法时,实际上你的想法是执行方法中的那些代码,方法的出现极大的提高了方法的复用性. Swift 工程的环 ...
- swift protocol 见证容器 虚函数表 与 动态派发
一.测试代码: //protocol DiceGameDelegate: AnyObject { //} // //@objc protocol OcProtocol{ // @objc fun ...
- swift派发机制的核心是确定一个函数能否进入动态派发列表
swift派发机制的核心是确定一个函数能否进入动态派发列表
- swift static与class修饰符:static不参与动态派发
static与class 都有类型成员的含义:相对于实例成员: static的另一个意思是静态派发:所以不能被继承. 要使用动态派发和继承的机制必须使用class继承. static的其它常见含义: ...
- swift 即使不使用oc的动态派发机制也应该借鉴isa类型识别机制
目前的消息派发机制真的很鸡肋. 简直是一堆狗屎. 类型信息中包含所有需要动态派发的函数:这个包含两类:类和protocol: 在编译时,首先搜索动态派发列表: 动态派发列表没有,在搜索静态派发列表: ...
- swift计算label动态宽度和高度
swift计算label动态宽度和高度 func getLabHeigh(labelStr:String,font:UIFont,width:CGFloat) -> CGFloat { let ...
- swift po 实现动态按钮2
// // ButtonViewController.swift // PopInstall // // Created by su on 15/12/11. // Copyright © 2 ...
- swift 该死的派发机制--待完成
swift 该死的派发机制 final static oc类型 多态类型 静态类型 动态函数 静态函数 nsobject: 1.缺省不再使用oc的动态派发机制: 2.可以使用nsobject暴露出来 ...
- swift potocol 作为参量时函数的派发顺序
1.检查protocol本体是否声明调用函数: 2.如果没有,检查protocol扩展是否有该函数:如果扩展中也没有,报错: 3.如果本体声明了函数,使用动态派发机制进行派发:扩展中的实现位于最末位.
随机推荐
- SpringBoot(4) SpringBoot热部署
热部署,就是在应用正在运行的时候升级软件,却不需要重新启动应用. 使用springboot结合dev-tool工具,快速加载启动应用 官方地址:https://docs.spring.io/sprin ...
- MySQL实验准备(一)--环境准备
MySQL实验脚本准备(一) python操纵数据库的实验环境 安装pip 1.下载脚本文件 [root@db01 .vnc]# wget https://bootstrap.pypa.io/get- ...
- Mini2440 通过 SPI 操作 OLED (裸板下使用 SPI 控制器)
在裸板下使用 SPI 的话,有两种方法可选: 使用 IO 口模拟 SPI 进行操作 使用 SPI 控制器进行操作 这里我们选用控制器的方式,简单方便. 初始化 SPI static void SPIC ...
- typeof() 和 GetType()区是什么
1.typeof(x)中的x,必须是具体的类名.类型名称等,不可以是变量名称. 2.GetType()方法继承自Object,所以C#中任何对象都具有GetType()方法,它的作用和typeof() ...
- 探秘小程序(8):scroll-view组件
按照官方文档的例子已经多scroll-view进行了说明,但是案例中没有样式 到时会出现一些问题,比如说,自己写的scroll-x并不能横向滚动,今天就来说一下这个问题: DEMO如下: html: ...
- 微信小程序支付最容易犯的坑notify_url(支付回调)
最近做了微信小程序支付,支付成功之后发现notify_url回调地址竟然没有访问. 检查了无数次代码,下单结果里面的回调地址看了又看,都没有错啊. 把回调地址复制出来到浏览器上面,外网也是可以访问的啊 ...
- C++ enum的使用
enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 默认情况下,枚举符的值从0开始,其后值总是前面一个+1. 即Sun=0,Mon=1,Tue=2,Wed=3,Thu= ...
- 从函数式编程到Promise
译者按: 近年来,函数式语言的特性都被其它语言学过去了.JavaScript异步编程中大显神通的Promise,其实源自于函数式编程的Monad! 原文: Functional Computation ...
- 解决element-ui的el-select组件文字超过宽度时不出现横向滚动条问题
我用的element-ui是V1.4.3. 目前遇到一个问题,在用el-select组件的时候,当选项的内容很长的时候,会撑开下拉菜单的宽度,这样影响美观.具体如下图所示: 解决这个问题的思路:设置下 ...
- IDEA项目搭建八——使用MybatisPlus简化数据库交互
一.MybatisPlus简化数据库交互 我们使用Mybatis发现需要在mapper.xml中写很多重复的简单CRUD(增删改查),使用MybatisPlus可以大大简化这部分代码,官方文档http ...