How to apply copy and mutableCopy to NSArray and NSMutableArray?

What is the difference between copy and mutableCopy when used in NSArray or NSMutableArray ?

This is my understanding; it is right?

 // ** NSArray ** NSArray *myArray_imu = [NSArray arrayWithObjects:@"abc", @"def", nil]; // No copy, increments retain count, result is immutable NSArray *myArray_imuCopy = [myArray_imu copy]; // Copys object, result is mutable NSArray *myArray_imuMuta = [myArray_imu mutableCopy]; // Both must be released later 



 // ** NSMutableArray ** NSMutableArray *myArray_mut = [NSMutableArray arrayWithObjects:@"A", @"B", nil]; // Copys object, result is immutable NSMutableArray *myArray_mutCopy = [myArray_mut copy]; // Copys object, result is mutable NSMutableArray *myArray_mutMuta = [myArray_mut mutableCopy]; // Both must be released later 
+60
cocoa-touch cocoa nsmutablearray nsarray nscopying
Jan 04 '10 at
source share
8 answers

copy and mutableCopy defined in different protocols ( NSCopying and NSMutableCopying respectively), and NSArray matches both. mutableCopy defined for NSArray (and not just NSMutableArray ) and allows you to make a mutable copy of an initially immutable array:

 // create an immutable array NSArray *arr = [NSArray arrayWithObjects: @"one", @"two", @"three", nil ]; // create a mutable copy, and mutate it NSMutableArray *mut = [arr mutableCopy]; [mut removeObject: @"one"]; 

Summary:

  • you can depend on the result of mutableCopy as mutable, regardless of the source type. In the case of arrays, the result should be NSMutableArray .
  • you cannot depend on the result of copy being mutable! copy ing a NSMutableArray can return an NSMutableArray since the source class, but copy for any arbitrary instance of NSArray will not.

Edit: re-read the source code in response to Mark Bessie's answer. When you create a copy of your array, you can of course change the original no matter what you do with the copy. copy vs mutableCopy affects the volatility of the new array.

Edit 2: Fixed my (false) assumption that NSMutableArray -copy will return NSMutableArray .

+64
Jan 04 '10 at 21:11
source share

I think you must have misinterpreted how copy and mutableCopy work. In your first example, myArray_COPY is an immutable copy of myArray. After making a copy, you can manipulate the contents of the original myArray and not affect the contents of myArray_COPY.

In the second example, you create a mutable copy of myArray, which means that you can modify any copy of the array without affecting another.

If I change the first example to try to insert / remove objects from myArray_COPY, it fails, as expected.




Perhaps think of a typical use case. It often happens that you can write a method that takes an NSArray * parameter and basically saves it for later use. You can do it as follows:

 - (void) doStuffLaterWith: (NSArray *) objects { myObjects=[objects retain]; } 

... but then you have a problem that the method can be called using NSMutableArray as an argument. The code that created the array can manipulate it between when the doStuffLaterWith: method is called and when you need to use the value. In a multi-threaded application, the contents of an array can even be modified during iteration over it, which can cause some interesting errors.

If you do this:

 - (void) doStuffLaterWith: (NSArray *) objects { myObjects=[objects copy]; } 

.. then the copy takes a snapshot of the contents of the array during the method call.

+8
Jan 04 '10 at
source share

The copy method returns an object created by implementing the NSCopying copyWithZone protocols:

If you send an NSString message with a copy:

 NSString* myString; NSString* newString = [myString copy]; 

The return value will be NSString (not mutable)




The mutableCopy method returns an object created by implementing the NSMutableCopying protocol mutableCopyWithZone:

By sending:

 NSString* myString; NSMutableString* newString = [myString mutableCopy]; 

The return value of WILL can be changed.




In all cases, the object must implement a protocol, which means that it will create a new copy object and return it to you.




In the case of NSArray, there is an additional level of complexity regarding shallow and deep copying.

A shallow copy of NSArray will only copy references to objects in the original array and place them in a new array.

As a result:

 NSArray* myArray; NSMutableArray* anotherArray = [myArray mutableCopy]; [[anotherArray objectAtIndex:0] doSomething]; 

Will also affect the object with index 0 in the original array.




A deep copy will actually copy the individual objects contained in the array. This is done by sending each individual object the message "copyWithZone:".

 NSArray* myArray; NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:myArray copyItems:YES]; 

Edited to remove my incorrect assumption about copying a mutable object

+6
Jan 04 2018-10-21T00:
source share
 NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES]; 

will create anotherArray , which is a copy from oldArray to two levels. If the oldArray object is an array. This usually applies to most applications.

Well, if we need True Deep Copy , which we could use,

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

This ensures that all levels are actually copied, while maintaining the variability of the original object at each level.

Robert Clarence D'Almeida, Bangalore, India.

+5
Sep 02 2018-11-11T00:
source share

You call addObject and removeObjectAtIndex in the original array, and not in a new copy of it. The call copy vs mutableCopy only affects the variability of the new copy of the object, not the original object.

+3
Jan 04 '10 at
source share

To just say

  • copy returns an immutable (cannot be changed) copy of the array,
  • mutableCopy returns a modified (may be modified) copy of the array.

Copying (in both cases) means that you get a new array "populated" with object references to the original array (that is, the same (original) objects refer to copies.

If you add new objects to mutableCopy, then they are unique to mutableCopy. If you delete objects from mutableCopy, they are deleted from the original array.

Recall the copy in both cases as a snapshot during the source array during the creation of the copy.

+2
Jul 05 '14 at 11:57
source share

Let's pretend that

 NSArray *A = xxx; // A with three NSDictionary objects NSMutableArray *B = [A mutableCopy]; 

Content B is an NSDictionary object, not an NSMutableDictionary, right?

0
May 12 '11 at 4:28
source share
 -(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that it. 

You must know the type of return of these files for copying, and when declaring a new object to be assigned, the return value must be immutable or mutable, otherwise the compiler will show you an error.

The object that was copied cannot be modified using the new one, now they are completely two different objects.

0
Aug 07 '13 at 6:28
source share



All Articles