首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带参考型项的Swift数组的CoW异常(写拷贝)

带参考型项的Swift数组的CoW异常(写拷贝)
EN

Stack Overflow用户
提问于 2020-05-03 16:00:11
回答 1查看 372关注 0票数 0

我的理解:

Swift中的数组是值类型。Swift中的数组和其他集合具有CoW (复制即写)机制,因此当数组作为参数传递给函数或简单地分配给另一个变量时,Swift实际上不会创建另一个数组副本,而只是将引用传递给同一个数组。在试图写入/修改数组时,斯威夫特将创建array的一个新副本(假设原始数组引用仍被强烈保存),并对数组的新副本执行写操作。

背景:

在这个问题中,我试图存储类实例(数组中的引用类型)

代码语言:javascript
复制
class TestClass {
    var name: String = "abcd"
    init(name: String) {
        self.name = name
    }
}

我正在创建TestClass的局部变量a(数组),并将其作为参数传递给someFunc

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

someFunc中,我将参数赋值给另一个变量anotherArray,并在anotherArray上执行append操作。正如预期的那样,数组的CoW启动并创建了一个数组的新副本,因此arrayanotherArray的内存地址是不同的。

代码语言:javascript
复制
func someFunc(array: [TestClass]) {
    var anotherArray = array
    anotherArray.append(TestClass(name: "mnop"))

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

正如预期的那样,在复制值类型时,所有内部引用类型也将被重新创建/复制,以证明

代码语言:javascript
复制
  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))
    }
}

显然,数组的内存地址是不同的(array !=== anotherArray),而且arrayanotherArray中所有项的内存地址也是不同的(array[i] !=== anotherArray[i])。

发行:

代码语言:javascript
复制
    func someFunc(array: [TestClass]) {
        var anotherArray = array
        anotherArray.append(TestClass(name: "mnop"))
        anotherArray[0].name = "Sandeep"
        debugPrint(array[0].name)
    }

有了明确的理解,数组和anotherArray是两个不同的副本,而且每个数组中的引用类型也是完全不同的,如果我将anotherArray[0].name的值更改为“san深处”,那么array[0].name仍然应该是"abcd“,但它会返回"Sandeep”。

为什么会这样呢?我是不是漏掉了什么?它与数组的特殊访问器mutableAddressWithPinnedNativeOwner有什么关系吗?

mutableAddressWithPinnedNativeOwner 阵列专用访问器

如果我正确理解它,而不是简单地在特定索引处提取值,复制它,修改它并替换原来的值,就像字典中的情况一样,mutableAddressWithPinnedNativeOwner只需要访问特定索引上的值的物理内存并对其进行修改。但是,当整个数组本身被修改时,这不会有什么区别:在这里我感到困惑

完整运行代码:

代码语言:javascript
复制
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)
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-03 20:42:03

看起来UnsafePointer(&value)返回了错误的值(可能是数组的头部或类似的东西)。我稍微改变了一下someFunc

代码语言:javascript
复制
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)
}

输出如下:

代码语言:javascript
复制
0x0000600003f29360
0x0000600003f29380
0x0000600003f29400

0x0000600003f29360
0x0000600003f29380
0x0000600003f29400
0x0000600003f29340

如您所见,两个数组都包含相同的对象,这是预期的行为。数组存储对TestClass对象(而不是值)的引用,并在CoW期间复制这些引用,但对象保持不变。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61577518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档