如何在Swift中执行“Deep Copy”?

问题描述 投票:20回答:3

在Objective-C中,可以通过以下方式进行深度复制:

 Foo *foo = [[Foo alloc] init];
 Foo *foo2 = foo.copy;

如何在Swift中进行深层复制?

swift deep-copy
3个回答
18
投票

Deep Copy

你的例子不是在StackOverflow上讨论的a deep copy。获得对象的真正深层副本通常需要NSKeyedArchiver

Swift and copying

NSCopying协议是Objective-C提供对象副本的方式,因为一切都是指针,你需要一种管理任意对象副本生成的方法。对于Swift中的任意对象副本,您可以提供一个便利初始化程序,在其中初始化MyObject另一个MyObject,并在init中将旧对象的值分配给新对象。老实说,这基本上是-copy在Objective-C中的作用,除了它通常必须在每个子对象上调用副本,因为Objective-C实践防御性复制。

let object = MyObject()
let object2 = MyObject(object)

Almost everything is pass-by-value. Almost.

但是,在Swift almost everything is pass-by-value(你应该真的点击前面提到的链接)所以对NSCopying的需求大大减少了。在游乐场试试这个:

var array = [Int](count: 5, repeatedValue: 0)
print(unsafeAddressOf(array), terminator: "")
let newArray = array
print(unsafeAddressOf(newArray), terminator: "")
array[3] = 3
print(array)
print(newArray)

您可以看到赋值不是指针的副本,而是实际上是一个新数组。对于围绕Swift的非复制值语义与结构和类相关的问题进行真正精心编写的讨论,我建议使用fabulous blog of Mike Ash

最后,如果您想听到Apple需要知道的一切,您可以观看the WWDC 2015 Value Semantics video。每个人都应该观看这个视频,它确实清除了Swift中处理内存的方式以及它与Objective-C的区别。


7
投票

如果Foo是一个实现NSCopying的Objective-C类,那么以下内容将起作用:

var foo2 = foo.copy();

-copy未在Foundation中使用属性表示法定义,因此即使您可以在Objective-C中使用点表示法,也不能将其视为Swift中的属性。实际上,你真的不应该使用点符号(即使它在语法上是合法的)因为-copy在逻辑上不是对象的属性,它是一种不带参数的方法来制作对象的副本。

注意,这不是深层副本,因为它不是Objective-C中的深层副本,除非该实现还复制了Foo实例的所有成员。


7
投票

为了我的遗忘自我:

对于其他任何寻找一种简单的方法来使用Swift进行树型对象的深层复制的人(父母可能/可能没有孩子,这些孩子可能/可能没有孩子等等)...

如果您为NSCoding设置了类(对于启动之间的持久数据),我可以使用该功能通过执行以下操作来对此树结构的任何特定实例执行深层复制...

(斯威夫特4)

class Foo: NSObject, NSCoding {
   var title = ""
   var children: [Foo] = []

   *blah, blah, blah*

   // MARK: NSCoding
   override public func encode(with coder: NSCoder) {
      super.encode(with: coder)
      coder.encode(title as Any?, forKey: "title")
      coder.encode(children as Any?, forKey: "children")
   }

   required public init?(coder decoder: NSCoder) {
      super.init(coder: decoder)
      self.title = decoder.decodeObject(forKey: "title") as? String ?? ""
      self.children = decoder.decodeObject(forKey: "children") as? [Foo] ?? []
   }

}

同时......在其他地方......

// rootFoo is some instance of a class Foo that has an array of child Foos that each can have their own same array

// Archive the given instance
let archive = NSKeyedArchiver.archivedData(withRootObject: rootFoo)

// Unarchive into a new instance
if let newFoo = NSKeyedUnarchiver.unarchiveObject(with: archive) as? Foo {

   // newFoo has identical copies of all the children, not references

}
© www.soinside.com 2019 - 2024. All rights reserved.