swift结构体发生深拷贝时,如何将其内部的class类型属性也进行深拷贝
我们知道swift值类型的变量在赋值操作后会放生深拷贝,即:赋值拷贝,而class类型的变量只会浅拷贝。我们看一个例子:
class MyClass { var list: [Int] init(_ list: [Int]) { self.list = list } } struct MyStruct { private var cls: MyClass var name: String init(cls: MyClass, name: String) { self.cls = cls self.name = name } func append(_ el: Int) { cls.list.append(el) } func printList() { for i in cls.list { print("\(name).cls.list: \(i)") } } } var s1 = MyStruct(cls: MyClass([1, 2]), name: "s1") var s2 = s1 s2.name = "s2" // 此时s2会发生深拷贝,s2成为了一个新的实例 s2.append(3) s2.append(4) s1.printList() print("----------------------") s2.printList()
打印结果如下:
s1.cls.list: 1 s1.cls.list: 2 s1.cls.list: 3 s1.cls.list: 4 ---------------------- s2.cls.list: 1 s2.cls.list: 2 s2.cls.list: 3 s2.cls.list: 4
我们通过打印结果可以看出,s2发生了深拷贝,s2.name被赋予了新的值"s2"。而cls属性是class类型,因此cls属性只是浅拷贝,s1与s2引用的是同一个cls实例。
很明显,我们不希望这样的事情发生,因为s1和s2是两个不同的实例,它们各自应该维护各自的数组列表,而不应该共享同一个数组列表实例。因此我们可以通过如下方式对cls进行深拷贝。
struct MyStruct { private var cls: MyClass var name: String init(cls: MyClass, name: String) { self.cls = cls self.name = name } mutating func append(_ el: Int) { if !isKnownUniquelyReferenced(&cls) { // cls存在多个实例强引用,说明当前MyStruct结构体发生了深度拷贝,而cls是class类型实例,所以cls只会进行浅拷贝,导致存在两个MyStruct结构体实例强引用一个cls实例 // 因此我们可以在这里将cls进行手动深拷贝 cls = MyClass(cls.list) } cls.list.append(el) } func printList() { for i in cls.list { print("\(name).cls.list: \(i)") } } } var s1 = MyStruct(cls: MyClass([1, 2]), name: "s1") var s2 = s1 s2.name = "s2" // 此时s2会发生深拷贝,s2成为了一个新的实例 s2.append(3) s2.append(4) s1.printList() print("----------------------") s2.printList()
打印日志:
s1.cls.list: 1 s1.cls.list: 2 ---------------------- s2.cls.list: 1 s2.cls.list: 2 s2.cls.list: 3 s2.cls.list: 4
我们通过输出日志可以看出,cls属性发生了深拷贝,我们通过修改append方法,增加了isKnownUniquelyReferenced判断,判断cls是否存在多个实例强引用,如果存在多个实例引用了cls,那说明s2发生了深拷贝,并对cls进行手动深拷贝。
要得到你必须要付出,要付出你还要学会坚持,如果你真的觉得很难,那你就放弃,但是你放弃了就不要抱怨,我觉得人生就是这样,世界真的是平等的,每个人都要通过自己的努力,去决定自己生活的样子。