iOS

Deep Copying of NSArray/NSDictionary/Any Object

When you use [array copy] or [array mutableCopy], you expect to get a complete new copy of the array/dictionary.

However, it doesn’t work that way.

Doing so will only gives you a shallow copy. What you usually want is a deep copy – that is to copy every object nested within.

Level 1 copies

If your array has only 1 level (it is not nested), then you can use this:

1
NSArray *deepCopyArray=[[NSArray alloc] initWithArray:someArray copyItems:YES];

Nested levels copies

But if you have an array nested in array.. then you need true deep copy, as Apple mentioned:

1
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];

NSKeyedArchiver will tranverse and archive all objects (which must conform to <NSCoding), then later unarchive to get a new copy.

NSCoding

If you have custom objects/models in the array, then you need to implement the protocol <NSCoding> (not NSCopying).

Note: NSArray, NSDictionary and other primitive types are already NSCoding-compliant.

There are 2 methods that you need to implement, which are just boring-tedious-code to declare which properties to be encoded, and later decoded and init with.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)encodeWithCoder:(NSCoder *)coder
{
    [coder encodeObject:self.foo forKey:@"foo"];
    [coder encodeObject:self.poo forKey:@"poo"];
    ...
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        self.foo     = [coder decodeObjectForKey:@"foo"];
        self.poo     = [coder decodeObjectForKey:@"poo"];
        ...
    }
    return self;
}

Comments