ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Swift-类与结构体(1)

2022-01-13 11:04:11  阅读:190  来源: 互联网

标签:调用 函数 方法 修饰符 objc func Swift 结构


Swift-类与结构体(2)

在这里, 我们从函数的角度来出发看类与结构体

一、函数相关的修饰符

1.mutating修饰符

前提:在Swift中class 和struct中都可以定义方法,但是在默认情况下值类型的属性是无法被自身的实例方法修改的

struct Student{
    var x = 0.0
    var y = 0.0
    func move(){
        self.x += deltaX
        self.y += deltaY
    }
    mutating func move(x deltaX:Double,y deltaY:Double){
        self.x += deltaX
        self.y += deltaY
    }
}

mutating修饰符可以允许值类型属性被修改,那么,我们从SIL中间代码的角度来看这两个的区别(第一行是第一个函数生成的,第二行是mutating函数生成的):

1 function_ref @$s4main7SHPointV3sumyyF : $@convention(method) (SHPoint) -> () 
2 function_ref @$s4main7SHPointV6moveBy6deltaX0E1YySd_SdtF : $@convention(method) (Double, Double, @inout SHPoint) -> () 

当不使用mutating时,函数参数传递的是SHPoint ,而使用mutating时,函数参数传递的是@inout SHPoint。那么这两者又什么区别呢?我们就需要了解一下inout这个修饰符

2.inout修饰符

inout即输入输出参数,他可以使函数内部修改外部实参的值(当函数运行之后,age的值需要在函数结束后依然保持改变)。

var age = 10

func modifyage(_age: inout Int){

    age += 1

}

modifyage(&age)

print(age)//11

inout修饰符实际上是引用传递。说明在使用mutating函数时,我们实际上传递的是实例的地址,所以此时结构体才可以被自身的实例方法修改自身的属性方法

3.final修饰符

final修饰符被标记时说明函数无法被重写,,使用静态派发(在编译之前,当前值类型的位置就已经被确定)的方式,不会在vTable(虚函数表)中出现,且对objc运行时不可见。final常用来优化类,如果类中的方法不会被重载,可以加final来使其变为静态调用。

4.dynamic修饰符

dynamic在修饰时为非objc类和值类型赋予动态性(在继承中可以被动态替换),派发方式采用函数表派发;另外dynamic不会改变函数的派发方式。

5.@objc修饰符

@objc修饰符使得swift函数暴露给objc运行时,但依然是函数表派发,如果将4+5结合到一起,也就是@objc+dynamic,就会形成消息派发机制,也就是OC中的objc_msgsend消息传递,这样就为swift和oc混编制造了机会。

二、方法调用

在OC中都是基于objc_msgsend函数来查找方法并进行调用的,而swift中又是如何调用的呢?我们通过lldb调试下面代码来看看

struct SHPoint{
    func test1(){}
    func test2(){}
    func test3(){}
}
var p = SHPoint()
p.test1()
p.test2()
p.test3()

 

 

 通过打断点,我们进入到汇编语言中发现,在调用结构体的方法时,其实是直接拿到函数的地址进行调用的。

三、类的方法

我们新建一个 Swift 项目,需要注意的是,一定要用真机跑,因为我们的 iOS 程序都是要装到手机上的,而手机的架构目前基本都是 arm64 的架构。

定义一个 SHPerson 类型,调用方法,打个断点,来看一下 Swift 类的方法在汇编的调用情况(bl,blr都表示跳转到某指令,blr表示无返回值)。

class LGTeacher{ 
    func teach(){}
func teach1(){}
func teach2(){} } class ViewController: UIViewController{ override func viewDidLoad() { let t = LGTeacher() t.teach()
t.teach1()
t.teach2() } }

 

 在上面的汇编代码中我们发现,其中的三次blr即为三次调用teach函数的过程,从汇编代码中我们发现,其实teach的调用过程是通过类拿到实例对象,同时拿到metadata的地址后通过内存平移的方式从而拿到函数地址再进行调用的。那么我们这些连续的函数地址又放在哪里呢?此时我们就需要了解一下虚函数表了。

1.虚函数表(VTable)

在swift对象组成中有一个metadata,这个结构体中有个typeDescriptor属性,这个属性是对类的一个详细的描述,在对这个属性的查找过程中可以发现,其内部有一个addVtable函数,在这个函数的实现中有这样一段代码:

 

在这里,计算 offset (结构体中的成员变量所有内存大小之和)之后,调用了 addInt32() 函数去计算添加方法到虚函数表的偏移量,最后再通过 for 循环,添加函数的指针。 总的来说:函数表添加函数的形式就是追加到数组的末尾。所以呢,函数表是按顺序连续存储类的方法的指针。

四、MachOView来分析类的方法存储

1.Mach-O文件

Mach-O(Mach Obejct)文件实际上是mac以及iOS上的可执行文件的格式,Mach-O文件的结构如下所示:

 

  •  文件头,表明该文件是Mach-O格式,指定目标架构,还有其他的一些文件属性信息,文件头信息影响后续的文件结结构安排
  • Load commands是一张包含很多内容的表,内容包括区域的位置,符号表,动态符号等
  • Data区负责记录代码和数据记录。Mach-O文件是以segment这种结构来组织数据的,一个segment可分为多个section,每个section可认为是代码、常量或者是其他的一些数据结构,在装载内存中时,是根据segment来做内存映射的。

2.Mach-O文件如何打开

首先,我们需要现在xcode中生成当前项目的projects文件(https://blog.csdn.net/u012275628/article/details/121140428?spm=1001.2014.3001.5501)

其次,我们点击projects中的app-show in finder-点击app-显示包内容-找到一个黑框的执行文件拖入MachOview中即可显示

 

swift5_types 这里存放的是结构体、枚举、类的 Descriptor,那么我们可以在 swift5_types 这里找到类的 Descriptor 的地址信息。 右侧展示地址信息。

 

前面的四个字节 90 FB FF FF 就是 类 的 Descriptor 信息(iOS 属于小端模式,所以 90 FB FF FF 要从右边往左读)

五、extension修饰符

我们先通过一个例子来看看带有extension修饰符的方法是怎么调用的?(汇编需要在真机的arm64架构上才能显示)

class Student{
    func t(){}
}
extension Student{
    func t2(){}
}

class ViewController: UIViewController{

    override func viewDidLoad() {
        var s = Student()
        s.t()
        s.t2()
}
}

通过对t2打断点,我们可以发现:extension修饰的方法是直接通过地址调用的,而没有加入到vtable中。

 

这样做的目的是为了优化,如果把extension修饰的方法在加入到函数表中需要进一步的考虑方法的存储位置,索引等等,但是如果我们直接静态派发就可以避免这些操作啦。

因此,对于extension调度的方法都是静态派发的。 

 

 

标签:调用,函数,方法,修饰符,objc,func,Swift,结构
来源: https://www.cnblogs.com/suanningmeng/p/15796679.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有