整理译自: When and How to Use Value and Reference Types in Swift https://khawerkhaliq.com/blog/swift-value-types-reference-types/
值类型 (Value) 与引用类型(Reference)
Swift 中结构体 (struct) 可定义属性与方法, 可以指定初始化方法, 实现协议, 除了继承, 类 (class) 能做的, 结构体几乎都能做, 那么什么时候用结构体, 什么时候用类就成了个问题, 换句话说, 就是在 Swift 中, 什么情况应该用值类型, 什么情况下用引用类型?
值类型: 结构体(Struct), 枚举(Enum), 元组(Tuple)
引用类型: 类(Class), 函数(Function)
语义
值类型: 变量与其所赋值分配的数据 (值) 逻辑统一, 一般将其视为储存在栈 (Stack) 上, 但实际上, 一部分数据在 CPU 寄存器, 其它一部分还是分配在堆 (Heap) 上. 可以感性地将其理解为, 值类型的数据 (值) 被包含在了变量中, 不能够单独被操作.
引用类型: 与值类型正好相反, 变量与其分配的数据 (实例) 是分离的, 引用类型的实例分配在堆 (Heap) 上, 变量分配在栈上, 仅持有该实例在内存中的地址, 可以有多个变量指向同一个实例, 该实例可独立地被其中任意指向它的变量操作.
- // 值类型
- struct CatStruct {
- var name: String
- }
- let a = CatStruct(name: "Whiskers")
- var b = a
- b.name = "Fluffy"
- print(a.name) // Whiskers
- print(b.name) // Fluffy
- // 引用类型
- class CatClass {
- init(name: String) {
- self.name = name
- }
- var name: String
- }
- let x = CatClass(name: "Whiskers")
- let y = x
- y.name = "Fluffy"
- print(x.name) // Fluffy
- print(y.name) // Fluffy
可变性 (Mutability) 概念的不同
区分变量 (variable) 可变性与实例 (instance) 可变性
由于值类型, 变量与实例在逻辑上是统一体, 因此值类型的变量可变性, 即其实例的可变性
引用类型, 变量与其所指向的实例是分离的, 因此变量的可变性, 仅仅代表其始终指向同一实例, 不代表其实例的可变性, 其实例中的具体数据 (属性) 等仍保持其自身的可变性.
值类型的特性
基于属性的可等性(Attribute-based equality)
没有身份标识与生命周期(Lack of Identity or lifecycle)
可替代性(Substitutability)
以上三个特性总结下来就是: 5 美元就是 5 美元, 到哪儿都是 5 美元
值类型的优点
高效: 引用类型在堆上分配, 相比栈上分配开支更大. Swift 中, 值类型基于其特性实现了 copy on write, 即当可变值类型真正发生改变那一刻时才会为其分配内存空间.
无副作用(可预测): 不同于引用类型的实例可被多个变量引用并操作, 值类型的特性可以有效避免代码的副作用.
线程安全
没有内存泄露的问题
易测试
值类型与引用类型在应用开发中如何设计使用
引用类型用于构建有身份标识 (identity) 的模型实体(model entity)
若该情况下采用值类型, 则易造成同一身份标识的数据 (属性) 不一致问题
值类型用于封装状态, 暴露行为, 表述业务逻辑
使用环境非常重要
基于属性的可等性的测试
值类型与引用类型的组合使用
将对象构造在值的基础上
总结
Swift 中提供了强大而高效的值类型, 让我们的一部分代码能够更高效, 无副作用, 并且线程安全. 在理解了值类型与引用类型的区别的前提下, 组合这两种数据类型, 更好更高效地达成应用目标.
关注下面的标签, 发现更多相似文章
iOS
Swift
安全
安装掘金浏览器插件
来源: https://juejin.im/post/5acb7b85518825558c47bd13