How to Copy Objects in Swift

how to make a deep copy of a swift array of class objects

As a simple statement, you could use code like this:

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

Note that the term "deepCopy" is a little misleading for what you're talking about. What if the array is heterogeneous and contains other containers like arrays, dictionaries, sets, and other custom container and "leaf" objects? What you should really do is to create a protocol DeepCopiable and make it a requirement that any object that conforms to DeepCopiable require that any child objects also conform to the DeepCopiable protocol, and write the deepCopy() method to recursively call deepCopy() on all child objects. That way you wind up with a deep copy that works at any arbitrary depth.

How to do Deep Copy in Swift?

Deep Copy

Your example is not a deep copy as discussed on StackOverflow. Getting a true deep copy of an object would often require NSKeyedArchiver

Swift and copying

The NSCopying protocol is the Objective-C way of providing object copies because everything was a pointer and you needed a way of managing the generation of copies of arbitrary objects. For an arbitrary object copy in Swift you might provide a convenience initializer where you initialize MyObject another MyObject and in the init assign the values from the old object to the new object. Honestly, that is basically what -copy does in Objective-C except that it usually has to call copy on each of the sub-objects since Objective-C practices defensive copying.

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

Almost everything is pass-by-value. Almost.

However, in Swift almost everything is pass-by-value (you should really click the aforementioned link) so the need for NSCopying is greatly diminished. Try this out in a Playground:

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)

You can see that the assignment is not a copy of the pointer but actually a new array. For a truly well-written discussion of the issues surrounding Swift's non-copy-by-value semantics with relation to structs and classes I suggest the fabulous blog of Mike Ash.

Finally, if you want to hear everything you need to know from Apple you can watch the WWDC 2015 Value Semantics video. Everyone should watch this video, it really clears up the way memory is handled within Swift and how it differs from Objective-C.

How can I properly copy objects from one Realm object to another object

What you want to do is use:

for record in postsDB.objects(PostModel.self) {
if !combinedDB.objects(PostModel.self).filter("postId == \(record.parentId)").isEmpty {
combinedDB.create(PostModel.self, value: record, update: false)
}
}

The create method is inherited from Object. It tells the target to create a new object. Use true if you want it to look to see if there is already a record there, and update it if there is.
PostModel is the Object type, record is what you want copied.

Edit: I added the if statement to provide more context. You didn't show your class definitions, so I was guessing. This is a working example. I ask for a set of records from DatabaseA and copy it to DatabaseB (postsDB to combinedDB).

So if the type of the object you're trying to insert is a List, I'd recommend you define a subclass of Object, and have at least the list you need as a property.

class TagList: Object {
dynamic var tag = ""
var list = List<PostModel>()

override class func primaryKey() -> String? {
return "tag"
}
}

Full working example illustrating: creating new objects, copying all objects to a second list, deleting from second list after copying, adding to first list (which didn't get anything deleted from it.

import Foundation
import RealmSwift

class Letter: Object {
dynamic var letter = "a"
}

class Letters: Object {
var letterList = List<Letter>()
}

class ListExample {
let listRealmStore = try! Realm() // swiftlint:disable:this force_try

func testThis() {
print(Realm.Configuration.defaultConfiguration.fileURL!)
listRealmStore.beginWrite()
addSingleItems() // add 3 objects to the DB

let firstList = Letters()
let allObjects = listRealmStore.objects(Letter.self)
for item in allObjects {
firstList.letterList.append(item)
}

let secondList = Letters()
let itemsToCopy = firstList.letterList
for item in itemsToCopy {
let obj = listRealmStore.create(Letter.self)
obj.letter = item.letter
secondList.letterList.append(obj)
}

let third = Letter()
third.letter = "Z"
listRealmStore.add(third)

firstList.letterList.append(third)
secondList.letterList.removeLast()
do {
try listRealmStore.commitWrite()
} catch let error {
print("couldn't commit db writes: \(error.localizedDescription)")
}

print("list one:\n\(firstList)")
print("list two:\n\(secondList)")
}

func addSingleItems() {

for letter in ["a", "b", "c"] {
let objectToInsert = Letter()
objectToInsert.letter = letter
listRealmStore.add(objectToInsert)
}
}
}

Results in:

list one:
Letters {
letterList = List<Letter> (
[0] Letter {
letter = a;
},
[1] Letter {
letter = b;
},
[2] Letter {
letter = c;
},
[3] Letter {
letter = Z;
}
);
}
list two:
Letters {
letterList = List<Letter> (
[0] Letter {
letter = a;
},
[1] Letter {
letter = b;
}
);
}


Related Topics



Leave a reply



Submit