Copy-on-Write技术
Swift针对标准库中的集合类型(Array、Dictionary、Set)进行优化。当变量指向的内存空间并没有发生改变,进行拷贝时,只会进行浅拷贝。只有当值发生改变时才会进行深拷贝。
/**
* 读取变量指向地址
*/
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
var array1 = [1, 2, 3, 4, 5, 6]
var array2 = array1
print(address(of: &array1))
print(address(of: &array2))
// 结果:
// 0x100527f60
// 0x100527f60
array1和array2都是指向地址是同一个空间,所以可以看出当前是浅拷贝
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
var array1 = [1, 2, 3, 4, 5, 6]
var array2 = array1
array2[0] = 2 // 值发生了改变
print(address(of: &array1))
print(address(of: &array2))
// 结果:
// 0x100593ec0
// 0x102800230
array1和array2指向了不同的空间,所以可以看出当前是浅拷贝
Copy-on-Write技术的实现
用set来进行讲解
final class Ref {
var val: T
init(_ v: T) {val = v}
}
struct Box {
var ref: Ref
init(_ x: T) {ref = Ref(x)}
var value: T {
get { return ref.val } // 读取操作
set { // 修改操作
if (!isUniquelyReferencedNonObjC(&ref)) { // 判断当前的类型值是否唯一的引用(即引用计算器为1)
ref = Ref(newValue) // 如果不是唯一的引用,则生成一个新的类型值并返回
return
}
ref.val = newValue // 如果是唯一的引用,则直接用当前的类型值进行修改
}
}
}
Array、Dictinary、Set每次进行修改前,都会通过类似isUniquelyReferencedNonObjC进行判断,判断是否是唯一的引用(即引用计数器为1)。若不为1,则创建新的类型值并返回。若是唯一的则直接赋值。
注意点
当Array、Dictionary、Set并没有进行修改操作值,建议把变量设置为let
参考:
https://swift.gg/2018/12/06/friday-qa-2015-04-17-lets-build-swiftarray/
https://juejin.im/post/5cbd31225188250a6e7e5d35