new2ios
new2ios

Reputation: 1350

How to create copy of NSArray and change it without affection original NSArray?

I need a copy of NSArray to store state of dates. I try to use mytableCopy which I understand makes copy which is independent of original object.

When I make changes to mutableCopy I have changes also in the original array.

Why?

My code is:

_nsarr = [[NSArray alloc] initWithArray:inputArray];
_nsMraa= [NSMutableArray alloc];
_nsMraa = [_nsarr mutableCopy];

Note: both arrays are properties of my object. inputArray is input param which is not use after that.

REMARK: one object is NSArray, other is NSMutableArray

Upvotes: 0

Views: 1137

Answers (3)

David Berry
David Berry

Reputation: 41236

As alluded to by Bharat and Milan, NSArray is an array of reference types, it contains an array of pointers. Calling mutableCopy will make a shallow copy of the array and make the copy mutable, the original will still be nonmutable. Neither mutableCopy nor copy will perform a deep copy on the CONTENTS of the array however. It is the ARRAY which becomes mutable or not, and not the CONTENTS of the objects held in the array.

Assuming the following:

@interface MyObject
- (int) state;
- (void) setState:(int) state;
@end

...

_nsarr = [NSArray arrayWithObject:[[MyObject alloc] initWithState]];
_nsmarr = [_nsarr mutableCopy];

At this point you have two distinct arrays, _nsarr and _nsmarr, one which isn't mutable, and one which is, HOWEVER, _nsarr[0] and _nsmarr[0] are still the same object, which means both that [_nsarr[0] setState:1] is valid, and that it has exactly the same effect as [_nsmarr[0] setState:1]

[_nsarr[0] setState:1];
NSLog("%d", [_nsmarr[0] state]);   // ==> 1

[_nsarr[0] setState:2];
NSLog("%d", [_nsmarr[0] state]);   // ==> 2

To copy the individual objects contained in the arrays, you need to create a "deep" copy of the array, which means to copy the contents (recursively) of the array as well as the array itself. There is no quick and easy way to create a deep copy of an array as it largely depends on how (if?) you can make a deep copy of the referenced objects. Bharat presents one approach (marginally costly since it serializes and deserializes the objects, and requires that they adhere to NSCoding) One approach might be something like:

_nsmarr = [NSArray withCapacity:[_nsarr count]];
for(MyObject* foo in _nsarr) {
    [_nsmarr addObject:[foo copy]];
}

Assuming that foo implements the NSCopying protocol, this is essentially identical to the initWithArray:copyItems: approach suggested by Milan:

_nsmarr = [[NSMutableArray alloc] initWithArray:_nsarr copyItems:YES];

Upvotes: 2

Bharat Modi
Bharat Modi

Reputation: 4180

If you need a true deep copy, such as when you have an array of arrays, you can archive and then unarchive the collection, provided the contents all conform to the NSCoding protocol. An example of this technique is shown below.

  • A true deep copy

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

Upvotes: 0

Milan Gupta
Milan Gupta

Reputation: 1181

Try this

_nsMraa = [[NSArray alloc]initWithArray:_nsarr copyItems:YES];

Upvotes: 1

Related Questions