通过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,所以认证了结构体是值类型

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

相关推荐
东坡肘子3 小时前
越来越慢的 App Review,拦住了谁? -- 肘子的 Swift 周报 #149
人工智能·swiftui·swift
冯汉栩20 小时前
Swift Control View,Label渐变颜色(源码)
开发语言·ios·swift
大熊猫侯佩5 天前
Xcode 预览新升级:arguments 让界面调试井井有条
swiftui·xcode·swift
大熊猫侯佩6 天前
WWDC26:把 SwiftUI Toolbar 真正握在手心里
swiftui·swift·apple
大熊猫侯佩6 天前
WWDC 26 全新 ResultsObserver:终于能在 View 外面盯着 SwiftData 了
swiftui·swift·apple
大熊猫侯佩6 天前
别再把大模型供在云端了,WWDC26 CoreAI 大模型下凡实战
ai编程·swift·wwdc
00后程序员张6 天前
有没有更轻量的 iOS 开发环境?快蝎kxapp轻量化路径与构成
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
sakiko_7 天前
Swift学习笔记39-实战注意事项
前端·笔记·学习·swift
东坡肘子7 天前
Apple Intelligence 已通过审核,即将在中国提供服务 -- 肘子的 Swift 周报 #148
人工智能·swiftui·swift
初级代码游戏9 天前
iOS开发 Swift 速记7:结构体和类
开发语言·ios·swift