conclusion

There is no true deep copy in Cocoa

Next, we need to clarify the definitions of shallow copy and deep copy (from Wiki)


Shallow copy

Create A new object B and copy A’s field values into B. If the field value in A is of the original type, copy the value of the original type into B. If the field value is a reference to an object, the reference is copied.

Deep copy

This is a recursive replication process. Fields are dereferenced, and a copy of the referenced object is generated. That is, deep Copy makes a complete copy of a new object (all referenced objects generate new instances).

(Note that there is no recursive processing in the figure, but it is important to note that the full deep copy has recursive processing logic because it is dereferenced.)


Copy

The copy method actually calls copyWithZone: the NSZone argument is no longer used by OC. So this is equivalent to an empty parameter. Check the copyWithZone:

The return object is implicitly retained, so the sender of the message is responsible for release. If mutable and immutable properties are considered for the object receiving the message, the copy returned is immutable. Otherwise, the exact nature of the copy is determined by the class.

The point is the last sentence, the exact nature of the copy depends on the class receiving the message.

Case 1:

NSMutableArray *arr = [NSMutableArray arrayWithObjects:@1The @2.nil];

id arr1 = [arr copy];  // ARr1 cannot respond to addObject: such a message arr1 is a new NSArray instance
Copy the code

Example 2:


NSString *str = @ "123";

str1  = [str copy]; // where STR and str1 are congruent, no new string objects are generated.
Copy the code

MutableCopy

The returned object is implicitly reserved by the sender, who is responsible for releasing it. The returned copy is mutable regardless of whether the original copy is mutable.

Here’s the thing. Many bloggers on the web think this is a deep copy, but it’s not. Because according to the documentation this is just a shallow copy. There is only an additional method to perform one-level-deep copy for container types, but it is not true deep copy

NSArray *deepCopyArray=[[NSArray alloc] initWithArray:someArray copyItems:YES];
Copy the code

Why copy and mutableCopy?

  • The ostensible reason is for type conversions (NSMutableArray, NSArray, NSMutableString, NSString, etc.).

  • The goal is to reduce unnecessary memory overhead (things that don’t need to be modified, and certainly don’t need to allocate new memory).

How to implement deep Copy

Only one-level-deep copy is provided for collection types. Such as:

NSArray *deepCopyArray=[[NSArray alloc] initWithArray:someArray copyItems:YES];
Copy the code

If you want to implement a true deep copy, Apple recommends:

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

Copy the code

You need to archive and de-archive, or serialize and de-serialize.

conclusion

  1. Immutable objects call copy and no new objects are generated because they are not necessary. The pointer points to the same address.

  2. An immutable object calls mutableCopy to generate a new object because it needs to be modified and the original object does not support modification.

  3. Mutable objects call copy, generating new objects because the expectation is to get an immutable object.

  4. A mutable object calls mutableCopy, and a new object is generated. Changes to the mutable object should not affect the original object, so a new object is generated.

The resources

  1. Copying Collections

  2. ObjectCopying

  3. MemoryManagement