Reputation: 3058
i have seen many attempts to answer this on Stackoverflooooooow and none have satisfied me.
i have a Person
class with only a public name
attribute that subclasses NSObject
. in the main
i run:
Person *alex = [[Person alloc] init];
alex.name = @"alex"
NSLog(@"name: %@ %p", alex.name, alex.name");
which will print to the console
2015-08-21 21:53:34.047 Test[29456:5960428] name: alex 0x108dfd640
the two methods i've found for copying both implement the copyWithZone:
selector from the <NSCopying>
protocol, which i place this in the Person
class.
1) the first version of this selector is:
- (id) copyWithZone:(NSZone *) zone
{
Person *personCopy = [[[self class] allocWithZone:zone] init];
personCopy.name = [self.name copyWithZone:zone];
// i've also tried: personCopy.name = [self.name copy];
return personCopy;
}
in the main i run
Person *aCopyOfAlex = [alex copy]
NSLog(@"name: %@ %p", aCopyOfAlex.name, aCopyOfAlex.name");
which logs
2015-08-21 21:53:34.047 Test[29456:5960428] name: alex 0x108dfd640
the Person
copy instance is different but the name attributes for the copy and original point to the same place.
2) the second version of this selector uses an archiver (which i guess takes some time - especially if i have a lot of attributes to deep copy across?) and then an unarchiver:
- (id) copyWithZone:(NSZone *) zone
{
Person *personCopy = [[[self class] allocWithZone:zone] init];
NSData *buffer = [NSKeyedArchiver archivedDataWithRootObject:self.name];
personCopy.name = [NSKeyedUnarchiver unarchiveObjectWithData:buffer];
return personCopy;
}
in the main i run again
Person *aCopyOfAlex = [alex copy]
NSLog(@"name: %@ %p", aCopyOfAlex.name, aCopyOfAlex.name");
which logs
2015-08-21 21:53:34.047 Test[29456:5960428] name: alex 0x7fa80969e4a0
this time both the Person
copy instance and the name attribute point to different places.
finally to a question! can someone say which method is correct (if either), please? it seems the second does what i want and would be an actual deep copy..
thanks!
Upvotes: 0
Views: 45
Reputation: 862
Although I have to agree with @rmaddy about the second one being overkill for this exact case, it is the only one (from the two you are posting) that will perform a deep copy.
Please see What is the difference between a deep copy and a shallow copy? for a nice explanation of what deep copying is.
If you had a mutable property say NSMutableArray *addresses
, the first method would leave you with two Person
instances sharing the same NSMutableArray
instances, which means that if you mutate addresses you would see changes in both Person instances, as they are indeed sharing the same array.
Please note that the second one will depend on whether the properties in Person are indeed archivable.
Upvotes: 0
Reputation: 318804
There's nothing wrong with your first bit of code. What you are seeing is an optimization done with strings. Since you started with an immutable string literal, copying it simply gives you back the same object. This isn't a problem because it is immutable.
Your second implementation of Person copyWithZone:
is overkill. Don't bother with the archiving.
Upvotes: 2