Objective-C: Copy Array, Modify Element (Object) in the Copy ONLY


I've read through many SO posts before asking this question and I'm guessing this answer was in there somewhere, but I didn't see it. I'm new to Objective-C and I'm trying to do a (seemingly) simple action that I can't figure out.

The general idea is that I have an NSArray filled with objects (specifically of type UIImageView). I want to copy that array, which I've done a number of ways (all successful).

After a copy it, I now have two arrays. I want to modify an object, say at index 2, ONLY in the copy.

So far it seems like, because the copy is merely copying the reference (or pointer), changing the object at index 2 will change it in both the copy and the original.

Does that make sense?

NSArray *originalArray = @[object1, object2];

Ways I've tried copying this array, so that I can achieve what I want:

NSMutableArray *originalArrayCopy = [NSMutableArray arrayWithArray:originalArray];

NSArray *originalArrayCopy = [originalArray copy];

NSMutableArray *originalArrayCopy = [[NSMutableArray alloc] initWithArray:originalArray];

And it seems that in each case, modifying an object from the copy also modifies it in the original.

NOTE: While NSArray is obviously immutable, the objects within my original array are mutable.

Best Solution

If the elements of your array conform to the NSCopying protocol, you can do this:

NSMutableArray *copy = [[NSMutableArray alloc] initWithArray:originalArray copyItems:YES];

This has the effect of sending copy to each element of the original array, storing the copies in the new array.

This is fine if each element returns a new, mutable copy when it receives the copy message. However, several Foundation classes (like NSMutableArray and NSMutableString) return immutable copies when they receive the copy message. If your elements belong to such a class, you need to send the mutableCopy message instead.

There's no built-in public message to do that. You can do it manually like this:

NSMutableArray *copy = [[NSMutableArray alloc] initWithCapacity:originalArray.count];
for (id element in originalArray) {
    [copy addObject:[element mutableCopy]];
Related Question