Q: 究竟什么时该用
struct
, 什么时候用class
呢?
A: 需要值语义的时候用struct
, 需要引用语义的时候用class
A: 最普遍的情况是构建数据模型时用struct
, 因为struct
支持写时复制, 在性能上比class更好
Swift中的类型系统
- 命名类型: protocol, enum, struct, class
- 复合类型: tuple, function
至于这些基本类型:Bool,Int,UInt, Float, Double, Character, String, Array, Set, Dictionary, Optional。他们是通过命名类型创建的。
值语义与引用语义的区别
一个比较容易理解的方式是, 这两者存储数据的方式不同,
- 对于值语义, 数据是直接保存在变量中,
- 对于引用语义, 变量存储的是数据的引用地址.
在拷贝数据时, 对于值语义, 拷贝的是数据本身, 对于引用语义, 拷贝的是数据的引用地址
// struct
struct Person {
var age = 10
}
var p = Person()
var p2 = p
printAddressForStruct(&p, &p2)
p.age = 20
p2.age // 10
printAddressForStruct(&p, &p2)
// class
class PersonClass: NSObject {
var age = 10
}
var pClass = PersonClass()
var pClass2 = pClass
printAddressForClass(pClass, pClass2)
pClass.age = 20
pClass2.age // 20
printAddressForClass(pClass, pClass2)
在这里, 我们可以通过打印对象的内存地址来帮助分析
Swift中打印内存地址的方法如下: 这里打印struct的方法和class的方法不同, 唯一的区别是传入的参数不同, &obj
和 obj
, 因为对于struct
, 在拷贝数据的时候会开辟新的内存空间, 所以需要是直接取地址作为参数
// 打印struct的地址
func printAddressForStruct(_ values: UnsafeRawPointer...){
values.forEach { (point) in
// String(unsafeBitCast(point, to: Int.self), radix: 16)
print(String(Int(bitPattern: point), radix: 16))
}
print("-----------------------")
}
// 打印class的地址
func printAddressForClass(_ values: Any...) {
// 将地址转为16进制数
values.forEach { (value) in
print(String(unsafeBitCast(value as AnyObject, to: Int.self),radix: 16))
}
print("-----------------------")
}
// 打印class的地址2
func printAddress(_ values: Any...) {
values.forEach { (value) in
// 将class reference 转化 为pointer
// 打印pointer 会直接打印内存地址
print(Unmanaged.passUnretained(value as AnyObject).toOpaque())
}
print("-----------------------")
}
控制台输出
11c1bfef0 11c1bfef8
-----------------------
11c1bfef0 11c1bfef8
对于struct, 已经为数据开辟了新的内存
604000015550 604000015550
-----------------------
604000015550 604000015550
对于class, 拷贝数据时是引用地址的拷贝, 他们操作的一直是同一块内存空间, 所以数据是一样的.
参考自
何时用 struct?何时用 class?
swift - 在swift中,打印可变内存地址
Swift中Struct, Class and Enum 对比
网友评论