简体   繁体   English

引用类型项目的 Swift 数组的 CoW(写入时复制)异常

[英]Anomaly in CoW (Copy on Write) of Swift Array with Reference type items

My understanding:我的理解:

Arrays in Swift are value types. Swift 中的 Arrays 是值类型。 Arrays and other collections in Swift has CoW (Copy on Write) mechanism so when an array is passed as an argument to a function or simply assigned to another variable, Swift will not actually create another copy of array rather simply passes the reference to same array. Arrays and other collections in Swift has CoW (Copy on Write) mechanism so when an array is passed as an argument to a function or simply assigned to another variable, Swift will not actually create another copy of array rather simply passes the reference to same array . On attempting to write/modify the array, swift will create a new copy of Array (Assuming that original array reference is still strongly held) and write operation will be performed on new copy of the array.在尝试写入/修改数组时,swift 将创建 Array 的新副本(假设原始数组引用仍被强保留)并且写入操作将在数组的新副本上执行。

Background:背景:

In this problem, I am trying to store class instances (reference types in Array)在这个问题中,我试图存储 class 实例(数组中的引用类型)

class TestClass {
    var name: String = "abcd"
    init(name: String) {
        self.name = name
    }
}

I am creating a local variable a (array) of TestClass and passing it as an argument to someFunc我正在创建一个局部变量 a (array) of TestClass并将其作为参数传递给someFunc

override func viewDidLoad() {
    super.viewDidLoad()
    var a = [TestClass(name: "abcd"), TestClass(name: "efgh"), TestClass(name: "ijkl")]
    debugPrint(UnsafePointer(&a))
    self.someFunc(array: a)
}

In someFunc I assign the argument to another variable anotherArray and perform append operation on anotherArray .someFunc ,我将参数分配给另一个变量anotherArray并在anotherArray上执行append操作。 As Expected CoW of Array kicks in and creates a new copy of Array so memory addresses of array and anotherArray are different.正如预期的 Array 的 CoW 启动并创建 Array 的新副本,因此arrayanotherArray的 memory 地址不同。

func someFunc(array: [TestClass]) {
    var anotherArray = array
    anotherArray.append(TestClass(name: "mnop"))

    debugPrint(UnsafePointer(&array))
    debugPrint(UnsafePointer(&anotherArray))
}

在此处输入图像描述

As expected, when a value type is copied, all the inner reference types will also be recreated/copied, to prove that正如预期的那样,当一个值类型被复制时,所有内部引用类型也将被重新创建/复制,以证明

  func someFunc(array: [TestClass]) {
    var anotherArray = array
    anotherArray.append(TestClass(name: "mnop"))

    for var value in array {
        debugPrint(UnsafePointer(&value))
    }

    for var value in anotherArray {
        debugPrint(UnsafePointer(&value))
    }
}

在此处输入图像描述

Clearly memory addresses of the arrays are different ( array !=== anotherArray ) and also memory addresses of all the items inside array and anotherArray are also different ( array[i] !=== anotherArray[i] )显然 arrays 的 memory 地址是不同的( array !=== anotherArray ),而且 memory 数组中所有项目的地址array[i] !=== anotherArray[i]arrayanotherArray中的所有项目的地址也是不同的(!

Issue:问题:

    func someFunc(array: [TestClass]) {
        var anotherArray = array
        anotherArray.append(TestClass(name: "mnop"))
        anotherArray[0].name = "Sandeep"
        debugPrint(array[0].name)
    }

With the clear understanding that array and anotherArray are two different copies and also reference types inside each array are completely different, one would expect if I change the value of anotherArray[0].name to "Sandeep", array[0].name should still be "abcd" but it returns "Sandeep"清楚地知道 array 和 anotherArray 是两个不同的副本,并且每个数组中的引用类型也完全不同,人们会期望如果我将anotherArray[0].name的值更改为“Sandeep”, array[0].name应该仍然是“abcd”,但它返回“Sandeep”

在此处输入图像描述

Why is that?这是为什么? Am I missing something here?我在这里错过了什么吗? Has it got anything to do with Array's Special Accessor mutableAddressWithPinnedNativeOwner ?它与 Array 的特殊访问器mutableAddressWithPinnedNativeOwner有什么关系吗?

Array's Special Accessor mutableAddressWithPinnedNativeOwner数组的特殊mutableAddressWithPinnedNativeOwner

If I understand it correctly, rather than simply pulling out the value at specific index, copying it, modifying it and replacing the original value like in case of Dictionary , mutableAddressWithPinnedNativeOwner simply access the physical memory of the value at specific index and modifies it.如果我理解正确,而不是像Dictionary那样简单地提取特定索引处的值,复制它,修改它并替换原始值, mutableAddressWithPinnedNativeOwner只需访问特定索引处值的物理 memory 并修改它。 But that shouldn't make a difference when entire array itself is modified:|但是当整个数组本身被修改时,这不应该有什么不同:| Am confused here在这里很困惑

Complete running code:完整运行代码:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        var a = [TestClass(name: "abcd"), TestClass(name: "efgh"), TestClass(name: "ijkl")]
        debugPrint(UnsafePointer(&a))
        self.someFunc(array: a)
        // Do any additional setup after loading the view.
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    func someFunc(array: [TestClass]) {
        var anotherArray = array
        anotherArray.append(TestClass(name: "mnop"))

        for var value in array {
            debugPrint(UnsafePointer(&value))
        }

        for var value in anotherArray {
            debugPrint(UnsafePointer(&value))
        }

        anotherArray[0].name = "Sandeep"
        debugPrint(array[0].name)
    }
}

Looks like UnsafePointer(&value) returns the wrong value (maybe it is the head of the array or something like this).看起来UnsafePointer(&value)返回了错误的值(可能是数组的头部或类似的东西)。 I changed the someFunc a little bit.我稍微改变了someFunc

func someFunc(array: [TestClass]) {
    var anotherArray = array
    anotherArray.append(TestClass(name: "mnop"))

    for var value in array {
        debugPrint(Unmanaged.passUnretained(value).toOpaque())
    }

    for var value in anotherArray {
        debugPrint(Unmanaged.passUnretained(value).toOpaque())
    }

    anotherArray[0].name = "Sandeep"
    debugPrint(array[0].name)
}

And the output is the following: output如下:

0x0000600003f29360
0x0000600003f29380
0x0000600003f29400

0x0000600003f29360
0x0000600003f29380
0x0000600003f29400
0x0000600003f29340

As you can see, both arrays contain the same objects, and this is the expected behavior.如您所见,两个 arrays 都包含相同的对象,这是预期的行为。 Array stores references to TestClass objects (not values) and copies these references during CoW, but the objects remain the same.数组存储对TestClass对象的引用(不是值)并在 CoW 期间复制这些引用,但对象保持不变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM