iOS - Deep Copy vs Shallow Copy

1. Deep copy and shallow copy

concept

There are two ways to copy objects: shallow copy and deep copy. As the name implies, shallow copy does not copy the object itself, but only copies the pointer to the object; deep copy directly copies the entire object memory to another memory.

To put it more simply: a shallow copy is a pointer copy; a deep copy is a content copy.

iOS deep copy vs shallow copy

Shallow copy of collection

There are many ways to shallow copy a collection. When you do a shallow copy, a retain message is sent to the original collection, the reference count is incremented by 1, and the pointer is copied to the new collection.

Now let's look at some examples of shallow copying:

1
2
3
NSArray *shallowCopyArray = [someArray copyWithZone:nil];
NSSet *shallowCopySet = [NSSet mutableCopyWithZone:nil];
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];

deep copy of collection

There are two ways to deep copy a collection. You can use initWithArray:copyItems: to set the second parameter to YES to deep copy, such as:

1
2
NSArray *shallowCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES];
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];

If you deep copy this way, every object in the collection will receive the copyWithZone: message. If the objects in the collection follow the NSCopying protocol, then the objects will be deep copied to the new collection. If an object does not conform to the NSCopying protocol, an attempt to deep copy this method will result in an error at runtime. copyWithZone: This copy method can only provide a layer of memory copy, not a true deep copy.

The second method is to archive the collection (archive), and then unarchive (unarchive), such as:

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

Second, copy and mutableCopy

Regardless of whether it is a collection class object or a non-collection class object, when receiving copy and mutableCopy messages, the following guidelines are followed:

  • copy returns an unmutable object; therefore, if you use the mutable object interface for the copy return value, it will crash;

  • mutableCopy returns mutable object;

The following will describe the copy and mutableCopy methods of non-collection objects and collection objects in detail.

Copy and mutableCopy of non-collection objects

System non-collection objects refer to objects such as NSString, NSNumber ....

Let's first look at an example of a non-collection class unmutable object copy

NSString *string =

1
2
3
@ "origin" ;
NSString *stringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];

print memory address

1
2
3
string =  0x1000eda78
stringCopy =  0x1000eda78
stringMCopy =  0x17407e8c0

It can be seen that the addresses of stringCopy and string are the same, indicating that the pointer is copied; and the address of stringMCopy is different from that of string, indicating that the content is copied;

Look at the mutable object copy example again

1
2
3
4
5
NSMutableString *mString = [NSMutableString stringWithString:@ "origin" ];
NSString *stringCopy = [mString copy];
NSMutableString *mStringCopy = [mString copy];
NSMutableString *mStringMCopy = [mString mutableCopy];
[mStringCopy appendString:@ "mm" ];

Running the above code will crash at the last line [mStringCopy appendString:@"mm"]; because the object returned by copy is an unmutable object, delete the line, run it again, and print the memory address

1
2
3
4
mString =  0x174266940
stringCopy =  0x1742294a0
mStringCopy =  0x1742294c0
mStringMCopy =  0x174266980

It will be found that the memory addresses of the four objects are different, indicating that the content is copied at this time.

From the above two examples, we can draw the following conclusions:

In a non-collection class object:

The copy operation on an unmutable object is a pointer copy, and the mutableCopy operation is a content copy;

Copy and mutableCopy of mutable objects are both content copies.

The code is simply expressed as follows:

[unmutableObject copy] // shallow copy

[unmutableObject mutableCopy] //deep copy

[mutableObject copy] //deep copy

[mutableObject mutableCopy] //deep copy

Copy and mutableCopy of collection class objects

Collection class objects refer to objects such as NSArray, NSDictionary, NSSet, etc.

Let's first look at an example of using copy and mutableCopy for the collection class unmutable object:

1
2
3
NSArray *array = @[@[@ "a" , @ "b" ], @[@ "c" , @ "d" ]];
NSArray *arrayCopy = [array copy];
NSMutableArray *arrayMCopy = [array mutableCopy];

print memory address

1
2
3
array =  0x1700353e0
arrayCopy =  0x1700353e0
arrayMCopy =  0x17024dad0

It can be seen that the addresses of arrayCopy and array are the same, while the addresses of arrayMCopy and array are different. It indicates that the copy operation performs a pointer copy, and mutableCopy performs a content copy. But it needs to be emphasized that the content copy here is just copying the array object, and the elements inside the array collection are still pointer copies.

Look at the example of mutable object copy again:

1
2
3
NSMutableArray *array = [[NSMutableArray alloc] initWithArray:@[@ "a" , @ "b" , @ "c" ]];
NSArray *arrayCopy = [array copy];
NSMutableArray *arrayMCopy = [array mutableCopy];

print memory address

1
2
3
array =  0x17405eed0
arrayCopy =  0x17405eea0
arrayMCopy =  0x17405ef00

As we expected, the memory addresses of arrayCopy, arrayMCopy and array are different, indicating that arrayCopy and arrayMCopy both copy the contents of array. Again, we can conclude that:

In a collection class object:

Copying an unmutable object is a pointer copy, and mutableCopy is a content copy;

Copy and mutableCopy of mutable objects are both content copies.

But: the content copy of the collection object is limited to the object itself, the object element is still a pointer copy.

The code is simply expressed as follows:

[unmutableObject copy] // shallow copy

[unmutableObject mutableCopy] //Single-layer deep copy

[mutableObject copy] //Single-layer deep copy

[mutableObject mutableCopy] //Single-layer deep copy

Explain again [the content copy of the collection object is limited to the object itself, and the object element is still a pointer copy] What does it mean?

For example, it is often encountered when we use MVC in our development. Now there is a mutableArray array that stores several Models. I want to create a new mutableArray1, assign the mutableArray to mutableArray1, and then change the Model in mutableArray1. But it doesn't affect mutableArray.

At this time, it is not possible to copy with copy or mutableCopy. As said, the content copy of the collection object is limited to the object itself, the object element is still a pointer copy, and the object element, that is, the Model in the array, is a pointer copy, so if it is changed, it will also be copied. Affects mutableArray.

So what to do? Please move to the deep copy of the collection above, there are two ways to solve this problem.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326846567&siteId=291194637