swift class的虚函数表、扩展、@objc修饰、虚函数的派发方式研究
swift class的虚函数表、扩展、@objc修饰的研究
工具:
swiftc -emit-sil BaseClass.swift | xcrun swift-demangle > ClassFunc.silgen
cat ClassFunc.silgen
目标:
1、@objc和@objc dynamic修饰的函数是否进入虚函数表;
2、虚函数的的派发机制是什么?函数的调用在编译器层面最终转化为apply调用;
3、extension中的缺省修饰函数是否进入虚函数表;
4、extension中的@objc修饰函数的行为;
5、结构体是否允许@objc修饰:
@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes

https://www.cnblogs.com/feng9exe/p/9460336.html
class NSObjectBase: NSObject {
func Msg_Normal(){ print("Msg_Normal") }
func Msg_Second(){ print("Msg_Second") }
func Msg_Third(){ print("Msg_Second") }
@objc func Msg_ObjcX(){}
@objc dynamic func Msg_Objc_Dynamic(){}
func callTest(){self.Msg_Normal()}
func callAgain(){self.Msg_Third()}
}
extension NSObjectBase{
@objc func OcExtensionFunc(){print("OcExtensionFunc")}
}
class DerivedOcClass:NSObjectBase{
override func OcExtensionFunc(){print("DerivedOcClass OcExtensionFunc")}
}
// NSObjectBase.Msg_Objc_DynamicX()
sil hidden @NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {
// %0 // user: %1
bb0(%0 : $NSObjectBase):
debug_value %0 : $NSObjectBase, let, name "self", argno 1 // id: %1
%2 = tuple () // user: %3
return %2 : $() // id: %3
} // end sil function 'NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> ()'
// @objc NSObjectBase.Msg_Objc_DynamicX()
sil hidden [thunk] @@objc NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> () : $@convention(objc_method) (NSObjectBase) -> () {
// %0 // users: %4, %3, %1
bb0(%0 : $NSObjectBase):
strong_retain %0 : $NSObjectBase // id: %1
// function_ref NSObjectBase.Msg_Objc_DynamicX()
%2 = function_ref @NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed NSObjectBase) -> () // user: %5
strong_release %0 : $NSObjectBase // id: %4
return %3 : $() // id: %5
} // end sil function '@objc NSObjectBase.NSObjectBase.Msg_Objc_DynamicX() -> ()'
// NSObjectBase.Msg_ObjcX()
sil hidden @NSObjectBase.NSObjectBase.Msg_ObjcX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {
// %0 // user: %1
bb0(%0 : $NSObjectBase):
debug_value %0 : $NSObjectBase, let, name "self", argno 1 // id: %1
%2 = tuple () // user: %3
return %2 : $() // id: %3
} // end sil function 'NSObjectBase.NSObjectBase.Msg_ObjcX() -> ()'
// @objc NSObjectBase.Msg_ObjcX()
sil hidden [thunk] @@objc NSObjectBase.NSObjectBase.Msg_ObjcX() -> () : $@convention(objc_method) (NSObjectBase) -> () {
// %0 // users: %4, %3, %1
bb0(%0 : $NSObjectBase):
strong_retain %0 : $NSObjectBase // id: %1
// function_ref NSObjectBase.Msg_ObjcX()
%2 = function_ref @NSObjectBase.NSObjectBase.Msg_ObjcX() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed NSObjectBase) -> () // user: %5
strong_release %0 : $NSObjectBase // id: %4
return %3 : $() // id: %5
} // end sil function '@objc NSObjectBase.NSObjectBase.Msg_ObjcX() -> ()'
sil hidden @NSObjectBase.NSObjectBase.callTest() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {
// %0 // users: %3, %2, %1
bb0(%0 : $NSObjectBase):
debug_value %0 : $NSObjectBase, let, name "self", argno 1 // id: %1
%2 = class_method %0 : $NSObjectBase, #NSObjectBase.Msg_Normal!1 : (NSObjectBase) -> () -> (), $@convention(method) (@guaranteed NSObjectBase) -> () // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed NSObjectBase) -> ()
%4 = tuple () // user: %5
return %4 : $() // id: %5
} // end sil function 'NSObjectBase.NSObjectBase.callTest() -> ()'
// NSObjectBase.callAgain()
sil hidden @NSObjectBase.NSObjectBase.callAgain() -> () : $@convention(method) (@guaranteed NSObjectBase) -> () {
// %0 // users: %3, %2, %1
bb0(%0 : $NSObjectBase):
debug_value %0 : $NSObjectBase, let, name "self", argno 1 // id: %1
%2 = class_method %0 : $NSObjectBase, #NSObjectBase.Msg_Third!1 : (NSObjectBase) -> () -> (), $@convention(method) (@guaranteed NSObjectBase) -> () // user: %3
%3 = apply %2(%0) : $@convention(method) (@guaranteed NSObjectBase) -> ()
%4 = tuple () // user: %5
return %4 : $() // id: %5
} // end sil function 'NSObjectBase.NSObjectBase.callAgain() -> ()'
sil_vtable NSObjectBase {
#NSObjectBase.Msg_Normal!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Normal() -> () // NSObjectBase.Msg_Normal()
#NSObjectBase.Msg_Second!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Second() -> () // NSObjectBase.Msg_Second()
#NSObjectBase.Msg_Third!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Third() -> ()// NSObjectBase.Msg_Third()
#NSObjectBase.Msg_Objc!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Objc() -> () // NSObjectBase.Msg_Objc()
#NSObjectBase.callTest!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callTest() -> () // NSObjectBase.callTest()
#NSObjectBase.callAgain!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callAgain() -> ()// NSObjectBase.callAgain()
}
sil_vtable DerivedOcClass {
#NSObjectBase.Msg_Normal!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Normal() -> () [inherited] // NSObjectBase.Msg_Normal()
#NSObjectBase.Msg_Second!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Second() -> () [inherited] // NSObjectBase.Msg_Second()
#NSObjectBase.Msg_Third!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Third() -> () [inherited] // NSObjectBase.Msg_Third()
#NSObjectBase.Msg_Objc!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.Msg_Objc() -> () [inherited] // NSObjectBase.Msg_Objc()
#NSObjectBase.callTest!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callTest() -> () [inherited] // NSObjectBase.callTest()
#NSObjectBase.callAgain!1: (NSObjectBase) -> () -> () : @NSObjectBase.NSObjectBase.callAgain() -> () [inherited] // NSObjectBase.callAgain()
}
apply担任函数绑定和派发的职责
那么阅读就显得简单多了, 可以看到最终对应到 testFunc函数调用的指令有两条.
%4 = class_method %2 : $MyClass, #MyClass.testFunc!1 : (MyClass) -> () -> (), $@convention(method) (@guaranteed MyClass) -> () // user: %5
%5 = apply %4(%2) : $@convention(method) (@guaranteed MyClass) -> ()
class_method: 该指令通过类的函数表来查找函数, 基于类的实际类型.apply: 传递参数并执行函数.
作者:MaizeJS
链接:https://www.jianshu.com/p/cfe7da01880d
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
swift class的虚函数表、扩展、@objc修饰、虚函数的派发方式研究的更多相关文章
- C++ 虚函数表解析
转载:陈皓 http://blog.csdn.net/haoel 前言 C++中 的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实 ...
- 对C++虚函数、虚函数表的简单理解
一.虚函数的作用 以一个通用的图形类来了解虚函数的定义,代码如下: #include "stdafx.h" #include <iostream> using name ...
- C++的虚函数表
这里的例子全部来自陈皓的C++ 虚函数表解析,经过修改的. 编译器:g++ (Ubuntu 4.9.2-10ubuntu13) 4.9.2 环境:ubuntu 15.04 64位系统(地址占8字节) ...
- 我理解的C++虚函数表
今天拜读了陈皓的C++ 虚函数表解析的文章,感觉对C++的继承和多态又有了点认识,这里写下自己的理解.如果哪里不对的,欢迎指正.如果对于C++虚函数表还没了解的话,请先拜读下陈皓的C++ 虚函数表解析 ...
- C++虚函数表原理
C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指 向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技 ...
- C++ 虚函数表解析(转载)
转载自:陈皓 http://blog.csdn.net/haoel/article/details/1948051/ 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型 ...
- 转载:C++ 虚函数表解析
目录(?)[+] 转载:http://blog.csdn.net/haoel/article/details/1948051# 前言 C++中 的虚函数的作用主要是实现了多态的机制.关于多态,简而 ...
- C++ 虚函数表与内存模型
1.虚函数 虚函数是c++实现多态的有力武器,声明虚函数只需在函数前加上virtual关键字,虚函数的定义不用加virtual关键字. 2.虚函数要点 (1) 静态成员函数不能声明为虚函数 可以这么理 ...
- C++虚函数及虚函数表解析
一.背景知识(一些基本概念) 虚函数(Virtual Function):在基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数.纯虚函数(Pure Virtual Functio ...
随机推荐
- Jmeter获取接口返回数组的长度
添加BeanShell PostProcessor来获取,具体代码如下: import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath ...
- [转]bootstrapValidator.js 做表单验证
本文转自:https://www.cnblogs.com/nele/p/5493414.html 作者:@nele本文为作者原创,转载请注明出处:https://www.cnblogs.com/nel ...
- T-SQL:CTE用法(十)
CTE 也叫公用表表达式和派生表非常类似 先定义一个USACusts的CTE WITH USACusts AS ( SELECT custid, companyname FROM Sales.Cust ...
- 4.移植uboot-使uboot支持DM9000网卡
在上一章,使uboot能够支持nor.nand 本节继续修改让uboot支持DM9000C网卡,便可以通过网络来传输文件 首先uboot已带有dm9000网卡的驱动,位于drivers/net/下的d ...
- 在UAP中如何通过WebView控件进行C#与JS的交互
最近由于项目需求,需要利用C#在UWP中与JS进行交互,由于还没有什么实战经验,所有就现在网上百度了一下,但是百度的结果显示大部分都是在Android和IOS上面的方法,UWP中的几乎没有.还好微软又 ...
- SQL Server 基本INSERT语句
1.基本INSERT语句,单行插入 如果没有列出列,则使一一对应. 2.多行插入 3.INSERT INTO ... SELECT 语句 要插入的语句是从其他表中查询出来的. 注意:数据类型得相同或者 ...
- vue路由传参的三种基本方式
现有如下场景,点击父组件的li元素跳转到子组件中,并携带参数,便于子组件获取数据. 父组件中: <li v-for="article in articles" @click= ...
- JS中数组去重的九方法
数组去重方法 方法一:运用set结构特点:存储的数据没有重复的,结果为对象,再用Array.from()转换成数组 var arr = [1,1,2,1,3,4,5] ...
- link标签链接CSS和@import加载的区别
link:基本语法 <link rel="stylesheet" href="路径"> @import 基本语法 <style> @im ...
- React 入门学习笔记整理(九)——路由
(1)安装路由 React-router React-router提供了一些router的核心api,包括Router, Route, Switch等,但是它没有提供dom操作进行跳转的api. Re ...