1. 程式人生 > 其它 >swift結構體發生深拷貝時,如何將其內部的class型別屬性也進行深拷貝

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進行手動深拷貝。

要得到你必須要付出,要付出你還要學會堅持,如果你真的覺得很難,那你就放棄,但是你放棄了就不要抱怨,我覺得人生就是這樣,世界真的是平等的,每個人都要通過自己的努力,去決定自己生活的樣子。