How can I make a deep copy in Objective-C?

Following the explanation at http://www.techotopia.com/index.php/Copying_Objects_in_Objective-C

"This can be achieved by writing the object and its constituent elements to an archive and then reading back into the new object."

@implementation ClassA

- (id)copyWithZone:(NSZone*)zone{
    NSData *buffer;
    buffer = [NSKeyedArchiver archivedDataWithRootObject:self];
    ClassA *copy = [NSKeyedUnarchiver unarchiveObjectWithData: buffer];
    return copy;
}
@end

You should add the copyWithZone: method in each class you want to be copiable.

NB: I wrote this by hand, watch out for typos.

-(id) copyWithZone:(NSZone *) zone
{
    ClassA *object = [super copyWithZone:zone];
    object.aInt = self.aInt;
    object.bClass = [self.bClass copyWithZone:zone];
    return object;
}

-(id) copyWithZone:(NSZone *) zone
{
    ClassB *object = [super copyWithZone:zone];
    object.bInt = self.bInt;
    object.cClass = [self.cClass copyWithZone:zone];
    return object;
}

-(id) copyWithZone:(NSZone *) zone
{
    ClassC *object = [super copyWithZone:zone];
    object.cInt = self.cInt;
    object.str = [self.str copy];
    return object;
}

I had custom classes with long lists of properties, so I iterated over them:

@interface MyClass : NSObject <NSCopying>

#import <objc/runtime.h>

-(id) copyWithZone: (NSZone *) zone {

    MyClass *myCopy = [[MyClass alloc] init];

    //deepCopy
    unsigned int numOfProperties;
    objc_property_t *properties = class_copyPropertyList([self class], &numOfProperties);

    for (int i = 0; i < numOfProperties; i++) {

       objc_property_t property = properties[i];
       NSString *propertyName = [[NSString alloc]initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
       [adressCopy setValue:[[self valueForKey:propertyName] copy] forKey:propertyName];
    }
    return myCopy;
}

All customClassProperties will need to implement this as well.


Objective-C on iOS doesn’t offer any direct language or library construct to switch between a shallow and a deep copy. Each class defines what it means to “get its copy”:

@implementation ClassA

- (id) copyWithZone: (NSZone*) zone
{
    ClassA *copy = [super copyWithZone:zone];
    [copy setBClass:bClass]; // this would be a shallow copy
    [copy setBClass:[bClass copy]]; // this would be a deep copy
    return copy;
}

@end

Of course you would have to do the same decision in ClassB and ClassC. If I am not mistaken, the usual semantics for a copy in Objective-C is to return a shallow copy. See also this question about copying arrays for more discussion of the topic.