deep copy for array of objects in swift

Since ordered is a swift array, the statement

 var orderedCopy = ordered

will effectively make a copy of the original array.

However, since Meal is a class, the new array will contain references to the same meals referred in the original one.

If you want to copy the meals content too, so that changing a meal in one array will not change a meal in the other array, then you must define Meal as a struct, not as a class:

struct Meal { 
  ...

From the Apple book:

Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.


To improve on @Kametrixom answer check this: For normal objects what can be done is to implement a protocol that supports copying, and make the object class implements this protocol like this:

protocol Copying {
    init(original: Self)
}

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

And then the Array extension for cloning:

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

and that is pretty much it, to view code and a sample check this gist


You either have to, as @MarioZannone mentioned, make it a struct, because structs get copied automatically, or you may not want a struct and need a class. For this you have to define how to copy your class. There is the NSCopying protocol which unifies that on the ObjC world, but that makes your Swift code "unpure" in that you have to inherit from NSObject. I suggest however to define your own copying protocol like this:

protocol Copying {
    init(original: Self)
}

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

which you can implement like this:

class Test : Copying {
    var x : Int

    init() {
        x = 0
    }

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

Within the initializer you have to copy all the state from the passed original Test on to self. Now that you implemented the protocol correctly, you can do something like this:

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

original.x = 10

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

This is basically the same as NSCopying just without ObjC

EDIT: Sadly this yet so beautiful protocol works very poorly with subclassing...