类是引用类型,存储在堆区;结构体是值类型,存储在栈区。类有继承特性;结构体没有。类实例可以被多次引用,有引用计数。结构体没有引用计数,赋值都是值拷贝。
一、swift中结构体和类的区别
- 类是引用类型,存储在堆区;结构体是值类型,存储在栈区。
- 类有继承特性;结构体没有。
- 类实例可以被多次引用,有引用计数。结构体没有引用计数,赋值都是值拷贝。
- 类有反初始化器(deinit)来释放资源。
- 类型转换允许你在运行时检查和解释一个类实例的类型。
值类型 vs 引用类型
结构体是值类型,实际上,Swift 中所有的基本类型:整数,浮点数,布尔量,字符串,数组和字典,还有枚举,都是值类型,并且都以结构体的形式在后台实现。
这意味着字符串,数组和字典在被赋值到一个新的常量或变量,或者它被传递到一个函数或方法中的时候,其实是传递了值的拷贝。这不同于 OC 的 NSString,NSArray 和 NSDictionary,他们是类,属于引用类型,赋值和传递都是引用。
值类型存储的是值,赋值时都是进行值拷贝,相互之间不会影响。而引用类型存储的是对象的内存地址,赋值时拷贝指针,都是指向同一个对象,即同一块内存空间。
1、结构体是值类型
swift
复制代码
struct Book {
var name: String
var high: Int
func turnToPage(page:Int) {
print(“turn to page \(page)”)
}
}
var s = Book(name: “程序员的自我修养”, high: 8)
var s1 = s
s1.high = 10
print(s.high, s1.high) // 8 10
这段代码中初始化结构体high为18,赋值给s1时拷贝整个结构体,相当于s1是一个新的结构体,修改s1的high为10后,s的age仍然是8,s和s1互不影响。
通过 lldb 调试, 也能够看出 s 和 s1 是不同的结构体. 一个在 0x100008080, 一个在 0x100008098.
swift
复制代码
(lldb) frame variable -L s
0x0000000100008080: (SwiftTest.Book) s = {
0x0000000100008080: name = “程序员的自我修养”
0x0000000100008090: high = 8
}
(lldb) frame variable -L s1
0x0000000100008098: (SwiftTest.Book) s1 = {
0x0000000100008098: name = “程序员的自我修养”
0x00000001000080a8: high = 10
}
2、类是引用类型
swift
复制代码
class Person {
var age: Int = 22
var name: String?
init(_ age: Int, _ name: String) {
self.age = age
self.name = name
}
func eat(food:String) {
print(“eat \(food)”)
}
func jump() {
print(“jump”)
}
}
var c = Person(22, “jack”)
var c1 = c
c1.age = 30
print(c.age, c1.age) // 30 30
如果是类,c1=c的时候拷贝指针,产生了一个新的引用,但都指向同一个对象,修改c1的age为30后,c的age也会变成30。
swift
复制代码
(lldb) frame variable -L c
scalar: (SwiftTest.Person) c = 0x0000000100679af0 {
0x0000000100679b00: age = 30
0x0000000100679b08: name = “jack”
}
(lldb) frame variable -L c1
scalar: (SwiftTest.Person) c1 = 0x0000000100679af0 {
0x0000000100679b00: age = 30
0x0000000100679b08: name = “jack”
}
(lldb) cat address 0x0000000100679af0
address:0x0000000100679af0, (String) $R1 = “0x100679af0 heap pointer, (0x30 bytes), zone: 0x7fff8076a000”
通过lldb调试,发现类的实例 c 和 c1 实际上是同一个对象, 再通过自定义命令 address 可以得出这个对象是在 heap 堆上.
而 c 和 c1 本身是2个不同的指针, 他们里面都存的是 0x0000000100679af0 这个地址.
swift
复制代码
(lldb) po withUnSAFePointer(to: &c, {print($0)})
0x0000000100008298
0 elements
(lldb) po withUnSAFePointer(to: &c1, {print($0)})
0x00000001000082a0
0 elements
延伸阅读:
二、SIL是什么
Swift Intermediate Language,Swift高级中间语言,Swift 编译过程引入SIL有以下优点:
- 完全保留程序的语义
- 既能进行代码的生成,又能进行代码分析
- 处在编译管线的主通道 (hot path)
- 架起桥梁连接源码与LLVM,减少源码与LLVM之间的抽象鸿沟
SIL会对Swift进行高级别的语意分析和优化。像LLVM IR一样,也具有诸如Module,Function和BasicBlock之类的结构。与LLVM IR不同,它具有更丰富的类型系统,有关循环和错误处理的信息仍然保留,并且虚函数表和类型信息以结构化形式保留。它旨在保留Swift的含义,以实现强大的错误检测,内存管理等高级优化。