了解Copy on Write在Swift开发时非常重要,因为这是Swift Standard Library的一个基础特性。
值类型:struct
,enum
,和tuple
,比如在调用函数时传递参数,就会发送副本拷贝
引用类型:class
,参数传递时是引用方式
代码举例:
struct S { var data: Int = -1 }
var a = S()
var b = a // a 是从 b 拷贝而来,因此a和b各自独立内存存储该结构体
a.data = 42 // 改变了 a 的值, b 不会有变动
println("\(a.data), \(b.data)") // 打印 "42, -1"
class C { var data: Int = -1 }
var x = C()
var y = x // x 是从 y 浅拷贝了
x.data = 42 // 修改x的值,y实例的值也会变更,因为他们共享同一份内存的值,只是分成了两个不同的指针指向
println("\(x.data), \(y.data)") // 因此打印的值是相同的 "42, 42"
Swift 中的 Copy-on-Write (简称 CoW) 是一种优化策略,用于减少不必要的数据复制,从而提高性能和内存使用效率。它主要应用于 Swift 的值类型,如字符串(String)、数组(Array)、字典(Dictionary)等。
示例:
基本概念:
- 当你将一个值类型的变量赋值给另一个变量时,Swift 默认进行浅拷贝。也就是说,两个变量实际上引用相同的内存地址。
- 只有在其中一个变量修改其内容时,Swift 才会进行实际的拷贝操作,也就是深拷贝。这确保了只有必要时才消耗资源进行拷贝。
注意事项:
-
1.不要提前优化:
Swift 的标准库已经为你实现了 CoW,因此大多数情况下你不需要手动优化。
只有在遇到性能瓶颈,且确定是由不必要的拷贝引起的时,才考虑实现自定义的 CoW。 -
2.正确管理引用类型:
如果你的值类型(如结构体或枚举)包含引用类型(如类实例),确保正确管理内存。
在修改引用类型属性时要特别小心,以免意外地改变所有共享该数据的实例。 -
3.避免无意的拷贝:
在处理大型数据结构时,避免无意中触发 CoW。例如,尽量不要在循环中修改数组元素的属性,因为这可能会导致重复的拷贝。 -
4.自定义类型的 CoW 实现:
如果你需要为自定义的值类型实现 CoW,确保只在必要时进行拷贝。
可以使用引用计数来跟踪变量的拷贝数量,当计数大于 1 时执行拷贝。 -
5.性能测试和分析:
使用性能分析工具(如 Xcode 中的 Instruments)来监控你的应用是否有效地使用了 CoW。
确保任何自定义的 CoW 实现不会引入新的性能问题。
CoW 是 Swift 语言中优化值类型的重要特性,正确理解和使用它可以帮助你写出更高效和更可靠的 Swift 代码。
自定义一个Copy on Write类
其中isKnownUniquelyReferenced
方法用于检测当时实例对象是否有引用,如果没有,则发生copy on write
class Storage {
var data: [YourDataType] // 替换 YourDataType 为你需要存储的类型
init(data: [YourDataType]) {
self.data = data
}
}
struct MyValueType {
private var storage: Storage
init(data: [YourDataType]) {
storage = Storage(data: data)
}
}
extension MyValueType {
private mutating func copyOnWrite() {
if !isKnownUniquelyReferenced(&storage) {
storage = Storage(data: storage.data)
}
}
mutating func append(_ item: YourDataType) {
copyOnWrite()
storage.data.append(item)
}
}