Swift方法调度之类的普通方法底层探究

目录
  • 1. 类的普通方法调度
  • 2. OC 继承链中的方法列表存储结构
  • 3. Swift 继承连中的函数表存储结构

1. 类的普通方法调度

写一个结构体和一个类,对比看看方法调用的方式:

// 结构体
struct PersonStruct {
    func changClassName() {}
}

let s = PersonStruct()
s.changClassName()

// 类
class PersonClass {
    func changClassName() {}
}

let c = PersonClass()
c.changClassName()

生成 SIL 代码:

【1】结构体及类的 SIL 代码:

与结构体不同的是:为PersonClass类自动生成了一个反初始化方法。

【2】执行方法的 SIL 代码:

在调用的方式中,可以看到类的方法,不是由function_ref修饰,而是class_method修饰。

【3】还有一个不同点是,SIL 中为 PersonClass 自动生成了sil_vtable:

由上面 SIL 代码,我们可以看出,SIL 为类的方法创建了 sil_vtable,并在调用时,用class_method来修饰。这样的类的方法调度,是Swift 中动态派发的一种方式,叫做函数派发。

这里由sil_vtable关键字声明的就是函数表。函数表初始化的源码如下:

从源码中看,函数表中的数据结构是一个数组,源码是以遍历的的方式去获取函数表内的函数的,所以函数表是按顺序存放类中可能是函数派发去执行的函数,但是不一定函数表内的函数都会被以函数派发的方式去调度。

2. OC 继承链中的方法列表存储结构

我们知道OC 中的方法是消息派发的方式。 每个对象中都有一个 isa 指针,指向自己的类。类中存放着该类实现的方法列表。本类方法列表中存放着本类实现的方法及父类方法列表的指针。在消息派发时,会先查找本来的方法列表,如果没找到,再去查找父类的方法列表,以此类推,来寻找方法的实现。

假设A类继承B类,B类继承C类,如下图所示:

3. Swift 继承连中的函数表存储结构

Swift 类中函数派发与消息派发类似, 所有类也会维护一个自己的函数表,不同的是所有未被复写的父类所实现的函数地址都会拷贝在这个表中, 而不是由一个指向父类方法表的指针替代,被重写的函数,在函数表中会指定为子类中的函数。由于少了一步指针寻址步骤, 在派发效率上要比基于消息的派发高效。

假设A类继承B类,B类继承C类,如下图所示:

代码验证一下:
Swift

class PersonClass: NSObject {
    override init() {
        super.init()
        @objc func changClassName7() {}
        dynamic func changClassName8() {}
    }
}

class PersonClassSub: PersonClass {
    func runSub() {}
    // 重写的函数,在函数表中会指定为子类中的函数
    override func changClassName7() {}
}

class PersonClassSubSub: PersonClassSub {
    func runSubSub() {}
}

到这里,证实2件事情:

  • Swift的函数表是按顺序存放的
  • 在类的继承关系中,函数表中存放所有的方法,由上到下,依次排列,先是父类的方法,再是子类的方法。

到此这篇关于Swift-方法调度-类的普通方法底层探究的文章就介绍到这了,更多相关Swift-方法调度内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Swift中初始化init的方法小结

    前言 我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的. 其实就是安全.在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题.虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误. 所以Swift有了超级严格的初始化方法.一方面,Swift强

  • swift 4自定义UITableCell的方法示例

    前言 本文主要给大家介绍了关于swift 4自定义UITableCell的相关内容,分享出来供大家参考学习价值,下面话不多说了,来一起看看详细的介绍吧 直接上图 新建MenuCell 创建一个类 MenuCell 继承 UITableViewCell 添加两个要实现的方法 override init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier:

  • swift中利用runtime交换方法的实现示例

    前言 Runtime介绍 学习一个东西至少要先知道它是个啥,你一定听说过"运行时是 Objective-C 的一个特色",这里的"运行时"就是指 runtime 了. 老的方式initialize现在已经不适用了,需要用新的方式代替. 思路: 定义一个启动的协议,在app完成启动的方法里把需要做method swizzle的类跑一边协议的方法 第一种 1.Step One protocol SelfAware: class { static func awake()

  • Swift方法调度之类的普通方法底层探究

    目录 1. 类的普通方法调度 2. OC 继承链中的方法列表存储结构 3. Swift 继承连中的函数表存储结构 1. 类的普通方法调度 写一个结构体和一个类,对比看看方法调用的方式: // 结构体 struct PersonStruct { func changClassName() {} } let s = PersonStruct() s.changClassName() // 类 class PersonClass { func changClassName() {} } let c =

  • Swift实现JSON转Model的方法及HandyJSON使用讲解

    背景: 很多时候,我们从服务端请求下的数据都是Json格式,我们需要拿这些数据显示到我们的UI界面. 因此,我们的做法基本都会先将json转为方便使用的数据模型,或者也可以直接转字典解决. 在OC中,我们有很多优秀的第三方库帮助我们实现,比如MJExtension.JSONModel等,这些库基本都是利用runtime实现读取属性名并利用kvc重新赋值属性. 在Swift中,由于runtime的局限,比较出名的有SwiftyJSON.ObjectMapper等. 其中: 1.SwiftyJSON

  • 详解Swift model 解析的两种方法

    详解Swift model 解析的两种方法 1. 常规解析方法 //懒加载声明一个LJNewsModel为数据的数组 lazy var ljArray : [LJNewsModel] = [LJNewsModel]() //MARK:-- 数据获取和解析 extension NewsViewController{ func requestNetData(){ /* 打印json数据 */ LJDownLoadNetImage.request("GET", url: "http

  • java动态方法调度实例分析

    本文实例讲述了java动态方法调度.分享给大家供大家参考,具体如下: 动态方法调度: 1. 访问一个引用型的变量的非静态方法,运行时与实际引用的对象的方法绑定. 2. 访问一个引用型的变量的静态方法,运行时与声明的类的方法绑定. 3. 访问一个引用型的变量的成员变量(包括静态变量和实例变量),运行时与声明的类的成员变量绑定. 第3点尤其注意啊,之前我从来没注意过啊 1. 非静态方法: public class Person { public String name; public void ge

  • php中laravel调度执行错误解决方法

    我们说laravel框架的功能性比较明确,作为全栈框架在代码的运行上是比较简洁的.在对laravel框架安装完成后,我们可以就其中的一些操作为大家展现.本篇要带来的是在laravel中的调度,分为两种不同目录的情况讨论,同时把可能在调度中会出现的错误情况,单独为大家呈现并解决. 1.不在laravel根目录(命令行操作前的地址) php /www/wwwroot/laravel6/artisan schedule:run /www/wwwroot/laravel/artisan 解释 /www/

  • Android 使用Pull方法解析XML文件的方法

    Pull解析方法给应用程序完全的控制文档该怎么样被解析.Android中对Pull方法提供了支持的API,主要是 复制代码 代码如下: org.xmlpull.v1.XmlPullParser;org.xmlpull.v1.XmlPullParserFactory; 二个类,其中主要使用的是XmlPullParser,XmlPullParserFactory是一个工厂,用于构建XmlPullParser对象.应用程序通过调用XmlPullParser.next()等方法来产生Event,然后再处

  • go语言方法集为类型添加方法示例解析

    目录 1概述 2为类型添加方法 2.1基础类型作为接收者 2.2结构体作为接收者 3值语义和引用语义 4方法集 4.1类型 *T 方法集 4.2类型 T 方法集 5匿名字段 5.1方法的继承 5.2方法的重写 6方法值和方法表达式 6.1方法值 6.2方法表达式 1概述 在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数,这种带有接收者的函数,我们称为方法(method).本质上,一个方法则是一个和特殊类型关联的函数. 一个面向对象的程序会用方法来表达其属性

  • Java线程中的常见方法(start方法和run方法)

    目录 start方法和run方法 示例代码 注意 sleep方法与yield方法 sleep yield 线程优先级 sleep的应用-防止cpu占用100% join方法 有实效的等待 interrupt方法 打断正常运行的线程,不会清空打断状态 守护线程 start方法和run方法 $start()$方法用来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到$cpu$时间片,就开始执行$run()$方法.而直接调用$run()$方法,仅仅只是调用了一个类里的方法,其本质上还

  • JavaScript使用链式方法封装jQuery中CSS()方法示例

    本文实例讲述了JavaScript使用链式方法封装jQuery中CSS()方法.分享给大家供大家参考,具体如下: 主要思路就是:返回this对象,将所获取的操作元素放入一个数组中.在原型中添加拓展方法 <html> <head> <title></title> </head> <body> <div id="one">aa</div> </body> <script typ

  • 浅谈Java泛型让声明方法返回子类型的方法

    泛型典型的使用场景是集合.考虑到大多数情况下集合是同质的(同一类型),通过声明参数类型,可免去类型转换的麻烦.本文将讨论本人阅读Spring Security源码时遇到的一个关于泛型递归模式的问题. 声明方法返回子类型 在Spring Security的源码里有一个ProviderManagerBuilder接口,声明如下 public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> ext

随机推荐