通过SIL理解Swift中的Struct

一、与class的不同点

age给定默认值

Swift 复制代码
/**结构体*/
struct FFHobbyGirls {
    var age = 10
    func hobbyGirls() {
        print("hobbyGirls")
    }
}
var t = FFHobbyGirls()

age不给定默认值

Swift 复制代码
/**结构体*/
struct FFHobbyGirls {
    var age: Int
    func hobbyGirls() {
        print("hobbyGirls")
    }
}
var t = FFHobbyGirls(age: 10)

结论: 相对于class来说,struct会自动给定初始化方法,如果是class的情况下,会报错

二、如果我们的属性有默认的初始值,那么我们的系统就不会提供默认的初始化方法了

在SIL角度来剖析一下原理: 打开项目文件夹目录

cd /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice

把 mian.swift编译成main.sil并打开(推荐使用vs code)

swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil && open main.sil No application knows how to open /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice/main.sil.

来看main.sil,提供了两个初始化方法

init(age: Int = 10) init()

swift 复制代码
struct FFHobbyGirls {
  @_hasStorage @_hasInitialValue var age: Int { get set }
  func hobbyGirls()
  init(age: Int = 10)
  init()
}

如果我自己实现了init方法

Swift 复制代码
struct FFHobbyGirls {
    var age = 10
    func hobbyGirls() {
        print("hobbyGirls")
    }
    init(age:Int) {
        self.age = age
    }
}

如果是这样的话,当前编译器就不会帮我生成init方法了,再次查看main.sil

Swift 复制代码
struct FFHobbyGirls {
  @_hasStorage @_hasInitialValue var age: Int { get set }
  func hobbyGirls()
  init(age: Int)
}

这个时候这里面就只有我们自己生成的初始化方法了

三、结构体是值类型

先了解什么是值类型:

  • 地址存储的就是值
  • 传递的过程中相当于传递了一个副本

例子:

Swift 复制代码
func test() {
    var age = 18
    var age2 = age //设置断点 ①
    age = 30 //设置断点 ②
    age2 = 45
    print("age=\(age),age2\(age2)")
}

var age = 18 意味着在栈区声明了一个地址来存储age变量,然后将18这个字面量给到当前的地址空间

在栈区创建的内存空间是由系统管理的 通过lldb调试来查看age的地址,这个地址很明显是个栈上的地址空间(高地址)

terminal 复制代码
(lldb) po withUnsafeMutablePointer(to: &age){print($0)}
0x00007ffeefbff410
0 elements

然后对这个内存进行格式化输出,在这个内存地址里面直接存储的我们的值18(0x0000000000000012 )

terminal 复制代码
(lldb) x/8g 0x00007ffeefbff410
0x7ffeefbff410: 0x0000000000000012 0x0000000000000000
0x7ffeefbff420: 0x00007ffeefbff440 0x0000000100002a14
0x7ffeefbff430: 0x00007ffeefbff468 0x0000000100015025
0x7ffeefbff440: 0x00007ffeefbff458 0x00007fff20393621

当放开设置的断点①,停留在断点②处的时候,将age赋值给了age2,等同于我直接把age里面的值18拿出来赋值给了age2,也就是说将18赋值给了age2

同样适用lldb调试看结果:

terminal 复制代码
(lldb) po withUnsafeMutablePointer(to: &age2){print($0)}
0x00007ffeefbff408
0 elements

(lldb) po withUnsafeMutablePointer(to: &age){print($0)}
0x00007ffeefbff410
0 elements

可以看出,age与age2这两个地址只差了8字节大小,栈空间地址分配的过程中是从高到低的,这也可以认证age是存储在栈上的 然后我在格式过输出age与age2的值:

terminal 复制代码
(lldb) x/8g 0x00007ffeefbff408
0x7ffeefbff408: 0x0000000000000000 0x0000000000000012
0x7ffeefbff418: 0x0000000000000000 0x00007ffeefbff440
0x7ffeefbff428: 0x0000000100002a14 0x00007ffeefbff468
0x7ffeefbff438: 0x0000000100015025 0x00007ffeefbff458
(lldb) x/8g 0x00007ffeefbff410
0x7ffeefbff410: 0x0000000000000012 0x0000000000000000
0x7ffeefbff420: 0x00007ffeefbff440 0x0000000100002a14
0x7ffeefbff430: 0x00007ffeefbff468 0x0000000100015025
0x7ffeefbff440: 0x00007ffeefbff458 0x00007fff20393621
(lldb) 

这个值也是一样的,在修改的过程中,修改的是当前独立地址里面的内存的值,也就意味着,在这个过程中,可以说age变量是一个值类型 同样的,看struct的例子:

Swift 复制代码
struct FFHobbyGirls {
    var age: Int = 18
    var age2: Int = 20
}

//结构体再赋值的过程中并不会共享状态
var t = FFHobbyGirls()
print("end")

通过lldb调试查看:

terminal 复制代码
(lldb) po t
▿ FFHobbyGirls
  - age : 18
  - age2 : 20

(lldb) po withUnsafeMutablePointer(to: &t){print($0)}
0x00000001000081a0
0 elements

(lldb) x/8g 0x00000001000081a0
0x1000081a0: 0x0000000000000012 0x0000000000000014
0x1000081b0: 0x0000000000000000 0x0000000000000000
0x1000081c0: 0x0000000000000000 0x0000000000000000
0x1000081d0: 0x0000000000000000 0x0000000000000000

可以看出,这个结构体的地址0x00000001000081a0中,直接存储的就是0x0000000000000012、0x0000000000000014,所以认证了结构体是值类型

注意点:尽量避免在值类型中包含引用类型

相关推荐
TouchWorld1 天前
iOS逆向-哔哩哔哩增加3倍速播放(2)-[横屏视频-半屏播放]增加3倍速播放
ios·swift
1024小神1 天前
xcode 中配置AR Resource Group并设置图片宽度等
ios·swiftui·ar·xcode·swift
Wcowin2 天前
OneClip 开发经验分享:从零到一的 macOS 剪切板应用开发
mac·swift·粘贴板
崽崽长肉肉2 天前
Swift中的知识点总结
ios·swift
代码不行的搬运工2 天前
面向RDMA网络的Swift协议
开发语言·网络·swift
大熊猫侯佩2 天前
拯救发际线行动:用 Swift 和 Image Playground 驾驭 AI 绘图
人工智能·ai·文生图·swift·图生图·imageplayground·apple 智能
linweidong3 天前
网易ios面试题及参考答案(下)
objective-c·swift·ios开发·切面编程·ios面试·苹果开发·mac开发
大熊猫侯佩3 天前
Swift 迭代三巨头(下集):Sequence、Collection 与 Iterator 深度狂飙
swift·编程语言·apple
大熊猫侯佩3 天前
Swift 迭代三巨头(中集):Sequence、Collection 与 Iterator 深度狂飙
swift·编程语言·apple
大熊猫侯佩3 天前
Swift 迭代三巨头(上集):Sequence、Collection 与 Iterator 深度狂飙
swift·编程语言·apple