swift

时间:2015-09-02 15:20:08

标签: swift deep-copy

我有这个名为Meal的课程

class Meal {
    var name : String = ""
    var cnt : Int = 0
    var price : String = ""
    var img : String = ""
    var id : String = ""

    init(name:String , cnt : Int, price : String, img : String, id : String) {
        self.name = name
        self.cnt = cnt
        self.price = price
        self.img = img
        self.id = id
    }
}

我有一系列的膳食:

var ordered = [Meal]()

我想复制那个数组然后对其中一个中的Meal实例进行一些更改,而不更改第二个中的Meal实例,我该如何制作它的深层副本?

此搜索结果对我没有帮助 How do I make a exact duplicate copy of an array?

5 个答案:

答案 0 :(得分:12)

要改进@Kametrixom,请回答以下问题: 对于普通对象,可以做的是实现支持复制的协议,并使对象类实现这样的协议:

protocol Copying {
    init(original: Self)
}

extension Copying {
    func copy() -> Self {
        return Self.init(original: self)
    }
}

然后是用于克隆的Array扩展:

extension Array where Element: Copying {
    func clone() -> Array {
        var copiedArray = Array<Element>()
        for element in self {
            copiedArray.append(element.copy())
        }
        return copiedArray
    }
}

就是这样,查看代码和示例检查这个gist

答案 1 :(得分:9)

由于ordered是一个快速数组,因此语句

 var orderedCopy = ordered

将有效地制作原始数组的副本。

但是,由于Meal是,因此新数组将包含引用 和原来提到的同样的饭菜。

如果你想复制膳食内容,那么在一个阵列中改变一顿饭不会改变另一个阵列中的一餐,那么你必须将膳食定义为结构,而不是类:

struct Meal { 
  ...

来自Apple book

  

使用struct创建结构。结构支持许多与类相同的行为,包括方法和初始化器。结构和类之间最重要的区别之一是结构在代码中传递时总是被复制,但类是通过引用传递的。

答案 2 :(得分:8)

正如@MarioZannone所提到的,您必须将其设为结构,因为结构会自动复制,或者您可能不需要结构并需要类。为此,您必须定义如何复制您的类。有一个NSCopying协议在ObjC世界中统一了这个协议,但这使得你的Swift代码“不可见”,因为你必须继承NSObject。但我建议您定义自己的复制协议,如下所示:

protocol Copying {
    init(original: Self)
}

extension Copying {
    func copy() -> Self {
        return Self.init(original: self)
    }
}

你可以像这样实现:

class Test : Copying {
    var x : Int

    init() {
        x = 0
    }

    // required initializer for the Copying protocol
    required init(original: Test) {
        x = original.x
    }
}

在初始化程序中,您必须将传递的original Test中的所有状态复制到self。既然你正确地实现了协议,你可以这样做:

let original = Test()
let stillOriginal = original
let copyOriginal = original.copy()

original.x = 10

original.x         // 10
stillOriginal.x    // 10
copyOriginal.x     // 0

这与没有ObjC的NSCopying基本相同

编辑:可悲的是,这个非常漂亮的协议在子类化方面效果很差......

答案 3 :(得分:0)

一种简单快捷的方法是将原始数组映射到新副本中:

let copyOfPersons: [Person] = allPersons.map({(originalPerson) -> Person in
        let newPerson = Person(name: originalPerson.name, age: originalPerson.age)
        return newPerson
    })

新人物将具有不同的指针,但值相同。

答案 4 :(得分:0)

基于之前的答案here

如果您有嵌套对象,即类的子类,那么您想要的是真正的深拷贝。

//Example
var dogsForAdoption: Array<Dog>

class Dog{
   var breed: String
   var owner: Person
}

所以这意味着在每个类(狗、人等)中实现 NSCopying。

你会为你的 20 节课这样做吗? 30..50..100 怎么样?你看对了吗?我们需要原生“它只是有效!”大大地。但不,我们没有。然而。

截至 2021 年 2 月,此问题尚无适当的解决方案。不过,我们有很多解决方法。

这是我一直在使用的一种,我认为限制较少的一种。

  1. 使您的类符合可编码
class Dog: Codable{
    var breed : String = "JustAnyDog"
    var owner: Person
}
  1. 创建这个助手类
class DeepCopier {
    //Used to expose generic 
    static func Copy<T:Codable>(of object:T) -> T?{
       do{
           let json = try JSONEncoder().encode(object)
           return try JSONDecoder().decode(T.self, from: json)
       }
       catch let error{
           print(error)
           return nil
       }
    }
}
  1. 每当您需要对象的真正深拷贝时调用此方法,如下所示:
 //Now suppose  
 let dog = Dog()
 guard let clonedDog = DeepCopier.Copy(of: dog) else{
    print("Could not detach Dog")
    return
 }
//Change/mutate object properties as you want
 clonedDog.breed = "rottweiler"
//Also clonedDog.owner != dog.owner, as both the owner : Person have dfferent memory allocations   

如您所见,我们捎带在 Swift 的 JSONEncoder 和 JSONDecoder 上,利用 Codable 的强大功能,无论对象下有多少嵌套对象,都可以进行真正的深度复制。只需确保您的所有类都符合 Codable。

虽然它不是理想的解决方案,但它是最有效的解决方法之一。