如何制作一个快速的类对象数组的深层副本

Posted

技术标签:

【中文标题】如何制作一个快速的类对象数组的深层副本【英文标题】:how to make a deep copy of a swift array of class objects 【发布时间】:2015-12-24 02:06:15 【问题描述】:

所以我知道swift数组是用struct实现的,它会自己自动复制。

我已经编写了我的课程 MyClass 并且我已经实现了 copyWithZone 来复制它

但是,我的 swift 数组包含我的 MyClass 对象,例如:

var array = [MyClass]()

当我想复制那个数组时

var anotherArray = array

它仍然没有调用MyClassObject.copyWithZone,以后如果我更改array中的对象属性,anotherArray也会反映更改。

如何在不编写 for 循环来迭代每个对象的情况下复制该

它没有被复制为deep copy for array of objects in swift,因为我不能使用 struct 来重写我的类。

【问题讨论】:

不,不是,答案是我必须使用 struct 来自动复制。但是我无法将其更改为 struct。这是一堂大课。 感谢您指出这一点,我将取消我的近距离投票 您可能需要考虑向 Array.阅读此页面上的问题和第一个答案:***.com/questions/24027116/… 但是,您无法避免使用显式或隐式循环。 谢谢!我会考虑延期 【参考方案1】:

作为一个简单的语句,您可以使用如下代码:

var copiedArray = array.map$0.copy()

请注意,“deepCopy”一词对您所说的内容有点误导。如果数组是异构的并且包含其他容器,如数组、字典、集合和其他自定义容器和“叶”对象,该怎么办?你真正应该做的是创建一个协议 DeepCopiable 并要求任何符合 DeepCopiable 的对象都要求任何子对象也符合 DeepCopiable 协议,并编写 deepCopy() 方法以递归调用 deepCopy()子对象。这样你就可以得到一个可以在任意深度工作的深层副本。

【讨论】:

这比 for 循环字少,这很棒;但是,为什么 swift 数组不能直接这样做呢?它应该知道它包含类对象并调用 copy()... 因为它不是这样工作的。拷贝是浅拷贝。通常这就是你想要的。就内存和时间而言,深度复制的成本要高得多。 所以结论是循环每个对象是唯一的解决方案? 深拷贝涉及复制数组中的每个对象。在某种程度上,您必须遍历成员并复制它们。即使 Swift 数组有一个 deepCopy 方法,该方法在内部也需要遍历数组的内容并复制它们。 map 语句为您提供所需的内容,而无需编写循环。【参考方案2】:

如果数组的元素是引用类型,则使该元素符合 NSCopying 并实现copyWithZone 方法。

class Book 
    var name: String

    init(_ name: String) 
        self.name  = name
    


extension Book: NSCopying 
    func copy(with zone: NSZone? = nil) -> Any 
        return Book(name)
    

现在实现一个数组扩展来进行深拷贝

extension Array where Element: NSCopying 
      func copy() -> [Element] 
            return self.map  $0.copy() as! Element 
      

测试代码库

let b1 = Book("Book1")
let b2 = Book("Book2")

let list = [b1, b2]
let clonedList = list.copy()

clonedList 现在是list 的副本,如果您对其中任何一个进行更改,则不会相互影响。

【讨论】:

【参考方案3】:

感谢 Duncan 的解决方案,这是一个使用它的扩展程序。 请注意,您的班级必须采用 NSCopying 协议。有关如何做到这一点,请参阅此处https://www.hackingwithswift.com/example-code/system/how-to-copy-objects-in-swift-using-copy

extension Array 
    func copiedElements() -> Array<Element> 
        return self.map
            let copiable = $0 as! NSCopying
            return copiable.copy() as! Element
        
    

【讨论】:

请注意,术语“deepCopy”有点误导。如果数组是异构的并且包含其他容器,如数组、字典、集合和其他自定义容器和“叶”对象,该怎么办?你真正应该做的是创建一个协议DeepCopiable,并要求任何符合DeepCopiable的对象要求任何子对象也符合DeepCopiable协议,并编写deepCopy()方法递归在所有子对象上调用deepCopy()。这样你就可以得到一个可以在任意深度工作的深层副本。 好点。我将把函数从 deepCopy() 重命名为 copiedElements() 以避免混淆。

以上是关于如何制作一个快速的类对象数组的深层副本的主要内容,如果未能解决你的问题,请参考以下文章

如何制作对象的深层副本?

如何制作由映射插件创建的剔除对象的深层副本

如何制作Java ArrayList的深层副本[重复]

对象数组的深拷贝

javascript 如何使用对象制作JavaScript数组的真实副本(无参考)

如何正确制作带有模板数组的类对象?