一、测试代码

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的动态派发的更多相关文章

  1. Swift 静态派发和动态派发

    前言 方法是 Swift 中的一个重要概念,方法允许你把需要复用的代码封装进方法中,这样当你调用方法时,实际上你的想法是执行方法中的那些代码,方法的出现极大的提高了方法的复用性. Swift 工程的环 ...

  2. swift protocol 见证容器 虚函数表 与 动态派发

    一.测试代码: //protocol DiceGameDelegate: AnyObject { //} // //@objc protocol OcProtocol{ //    @objc fun ...

  3. swift派发机制的核心是确定一个函数能否进入动态派发列表

    swift派发机制的核心是确定一个函数能否进入动态派发列表

  4. swift static与class修饰符:static不参与动态派发

    static与class 都有类型成员的含义:相对于实例成员: static的另一个意思是静态派发:所以不能被继承. 要使用动态派发和继承的机制必须使用class继承. static的其它常见含义: ...

  5. swift 即使不使用oc的动态派发机制也应该借鉴isa类型识别机制

    目前的消息派发机制真的很鸡肋. 简直是一堆狗屎. 类型信息中包含所有需要动态派发的函数:这个包含两类:类和protocol: 在编译时,首先搜索动态派发列表: 动态派发列表没有,在搜索静态派发列表: ...

  6. swift计算label动态宽度和高度

    swift计算label动态宽度和高度 func getLabHeigh(labelStr:String,font:UIFont,width:CGFloat) -> CGFloat { let ...

  7. swift po 实现动态按钮2

    // //  ButtonViewController.swift //  PopInstall // //  Created by su on 15/12/11. //  Copyright © 2 ...

  8. swift 该死的派发机制--待完成

    swift 该死的派发机制 final static oc类型 多态类型 静态类型 动态函数  静态函数 nsobject: 1.缺省不再使用oc的动态派发机制: 2.可以使用nsobject暴露出来 ...

  9. swift potocol 作为参量时函数的派发顺序

    1.检查protocol本体是否声明调用函数: 2.如果没有,检查protocol扩展是否有该函数:如果扩展中也没有,报错: 3.如果本体声明了函数,使用动态派发机制进行派发:扩展中的实现位于最末位.

随机推荐

  1. 年终培训关于磁盘冗余阵列、热备、群集、负载均衡、云计算、F5、Nginx等的概念和基本原理

    在系统部署实施过程中,客户往往会关注系统的可用性方面的指标. 对于一个具备高可用性的系统来说, 多机部署方案是必不可少的. 我们这个知识分享,就从多个不同层面来介绍多机部署方案. ---------- ...

  2. Maven教程1(介绍安装和配置)

    官网地址:http://maven.apache.org/ 1.Maven介绍 1.1为什么需要使用Maven 之前学Spring和SpringMVC的时候我们需要单独自己去找相关的jar. 这些ja ...

  3. [JZOJ5984] 仙人掌

    Description Solution 标算我并不会... 考虑一种根号思想 首先以 \(1\) 为根dfs整棵树 那么在任意时刻一个点的儿子的权值种类最多只会有 \(\sqrt m\) 种. 可以 ...

  4. RockChip RK3326 系统编译问题总结

    1. 序言 本文主要记录了RK3326平台系统编译过程中遇到的各种问题,并加以解决! 环境: 宿主Linux:Ubuntu 16.04 目标机:RK3326 (64bit) Toolchain:gcc ...

  5. 【转】java String.split()函数的用法分析

      在java.lang包中有String.split()方法的原型是: public String[] split(String regex, int limit) split函数是用于使用特定的切 ...

  6. C# 语言历史版本和特性

    C# 语言版本和对应特性,以及发布时间,.Net Framework 版本和 VS 版本 C# 4.0 和C# 5.0 熟悉点吧, VS10 ,VS12 和13 .Net Framework 4.0 ...

  7. WebFrom 小程序【分页功能 】

    实现分页展示功能 基本功能:上一页.下一页.首页.尾页.跳转 两个重要的变量 1.每页显示几条数据  2.现在是第几页    方法 } /*表格样式*/ .tab { width: %; backgr ...

  8. 关于wsgi协议的理解

    基础概念 首先要了解 WSGI 规范的概念,WSGI(Web Server Gateway Interface)规范描述了web server(Gunicorn,uWSGI等)如何与web appli ...

  9. Tarjan中栈的分析与SLT栈的实现

    首先看一下手写的栈: do{ printf("%d ",stack[index]); visit[stack[index]]=; index--; }]);//出栈,并且输出. p ...

  10. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...