Hello,
I’m running into a problem in my app. I have a top-level class called “AllLists”. This class contains a member which is an array of “ListGroup” objects. The ListGroup class contains an array of “MainTasks” objects… and so on…
The problem I have is that once I initialize an instance of the AllLists class (say, for example I call it “lists”), if I try to make a copy of that lists class and save it under a different name (say it’s called “newLists”), both classes end up sharing the same memory addresses. So any change to a member of one class affects the other class.
I tried googling this a big and found the Copyable protocol. I tried implementing this but it seems that only the top-level object (the AllLists class) gets a new memory address when I copy the “lists” object to the “newLists” object.
It seems that the embedded classes within the copied instance of the “lists” object still share the same memory addresses as the original instance of AllLists.
What is the best approach to handle this?
Are the classes within AllLists also copyable
? My understanding of deep copy is that not only the top level but all contained classes must be copyable.
This is a tricky subject in Swift and is slightly complicated by classes always being reference types. What does the “exact equality” operator (===) tell you about the class and its copy?
Hi Adam,
Because the instance of the top-level class uses the Copyable protocol, when I create the new object called “newLists”, it has a different memory address. I confirmed this by using the === operator. The problem is that every single object that newLists contains has the exact same memory address as all the objects within the lists object. Please see below for more information.
Thanks,
Jason
Here’s the top-level class definition:
Import Foundation
class AllLists : Copyable {
init() {
}
required init(instance: AllLists) {
self.listGroups = instance.listGroups
}
var listGroups = Array<ListGroup>()
func addListGroup(groupName : String){
let newListGroup = ListGroup(newListGroupName: groupName)
listGroups.append(newListGroup)
}
func removeListGroup(groupIndex : Int){
listGroups.remove(at: groupIndex)
}
func getNumListGroups() -> Int {
return listGroups.count
}
func printOutListGroups(){
let x = getNumListGroups()
if x > 0 {
for x in 0..<getNumListGroups() {
print("list groups at index \(x) is: \(listGroups[x].name)")
}
}
}
func purge(){
self.listGroups.removeAll()
}
}
In one of my view controllers, I added the protocol and the extension in order to allow me to copy the object of type AllLists:
protocol Copyable {
init(instance: Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(instance: self)
}
}
In each of my other classes (AllLists → ListGroups → MainTask → SubTasks), I added the necessary init method to facilitate the copying (the statements inside the init method differ based on what I’m trying to do in each of the classes; this example shows the AllLists init method):
required init(instance: AllLists) {
self.listGroups = instance.listGroups
}
This is the problem (probably). Because once I copy the object of type AllLists, it hits this initialization method and it says: “Set the listGroups array equal to the listGroups array from the object you are copying from.”
How do I tell it “Make a copy of the listGroups array and put it into the new instance of type AllLists?”. I would then need to do this same thing all the way down the chain…
I’m totally confused 
Does anyone know the answer to this? Any help would be great.
Well this is what I did in Objective-C, but have not taken the time to map to Swift. If Swift has a NSKeyedArchiver type method, maybe you can work it out from this example. Also, see here: Copying Collections
// iphone - how to do true deep copy for NSArray and NSDictionary with have nested arrays/dictionary? - Stack Overflow
NSData *buffer;
NSMutableDictionary *_dict1, *_dict2;
// Deep copy “all” objects in _dict1 pointers and all to _dict2
buffer = [NSKeyedArchiver archivedDataWithRootObject: _dict1];
_dict2 = [NSKeyedUnarchiver unarchiveObjectWithData: buffer];
– Rick