For deep copy and shallow copy, see iOS – Deep copy and Shallow copy Exploration and Verification

  1. As we know from the previous chapter:
  • Copy: Shallow copy for NSArray and deep copy for NSMutableArray
  • MutableCopy: always a deep copy
  • Elements in a collection object are shallow copies regardless of depth
  1. The main exploration of this paper
  • Copy elements in NSArray

Through this article you will know

  • Deep copy NSArray
  • Deep copy of Person in NSArray
  • Deep copy the nickname of the element Person in NSArray

This article is more code, it is recommended to follow the code patiently step by step investigation, there will be a lot of goods

To explore the process

1. The system Api

– (instancetype)initWithArray:(NSArray

*)array copyItems:(BOOL)flag Where copyItems:(BOOL)flag indicates whether to copy elements. Let’s test the code first

NSString *str1 = @"hello world"; NSMutableString *str2 = [NSMutableString stringWithString:@"hello world"]; NSArray *array1 = [NSArray arrayWithObjects: str1, str2, nil]; NSMutableArray *array2 = [[NSMutableArray alloc] initWithArray:array1 copyItems:true]; NSLog(@"\n array1 = %p class = %@ \n", array1, [array1 class]); NSLog(@"\n array2 = %p class = %@ \n", array2, [array2 class]); NSLog(@"\n\n======== element is String ======== "); NSLog(@"\n obj0 = %p class = %@ \n", array1[0], [array1[0] class]); NSLog(@"\n obj0 = %p class = %@ \n", array2[0], [array2[0] class]); NSLog (@ "\ n \ n = = = = = = = = element is mutableString = = = = = = = ="); NSLog(@"\n obj0 = %p class = %@ \n", array1[1], [array1[1] class]); NSLog(@"\n obj0 = %p class = %@ \n", array2[1], [array2[1] class]);Copy the code

View the output (I marked the output with line for comparison)

2021-05-09 10:59:16.343163+0800 AlgorithmDemo[994:51756] array1 = 0x100607650 class = __NSArrayI (line1) array2 = 0x1006074A0 Class = __NSArrayM (line2) ======== The element is String ======== obj0 = 0x100008220 class = __NSCFConstantString (line3) obj0 = 0x100008220 class = __NSCFConstantString (line4) ======== the element is mutableString ======== obj0 = 0x100606330 class = __NSCFString (line5) obj0 = 0x100605430 class = __NSCFString (line6)Copy the code

According to the output, we get the system initWithArray: copyItems: method as follows

  • This method is a deep copy of an NSArray object(Strictly speaking, this is not called copying, but creating new objects)(, line1 line2)
  • When the elements in the array areImmutable objectIs executed on the elementShallow copy(line3 line4)
  • When the elements in the array areThe variable objectIs executed on the elementDeep copy(line4 line5)

– (instancetype)initWithArray:(NSArray

*)array copyItems:(BOOL)flag – (instancetype)initWithArray:(NSArray

*)array :(BOOL)flag

File 2.

If we archive and unfile Array, what will the result be? Let’s test the code

NSString *str1 = @"hello world"; NSMutableString *str2 = [NSMutableString stringWithString:@"hello world"]; NSArray *array1 = [NSArray arrayWithObjects: str1, str2, nil]; NSMutableArray *array2 = [[NSMutableArray alloc] initWithArray:array1 copyItems:true]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array1]; NSMutableArray *array3 = [NSKeyedUnarchiver unarchiveObjectWithData:data]; NSLog(@"\n array1 = %p class = %@ \n", array1, [array1 class]); NSLog(@"\n array2 = %p class = %@ \n", array2, [array2 class]); NSLog(@"\n array3 = %p class = %@ \n", array3, [array3 class]); NSLog(@"\n\n======== element is String ======== "); NSLog(@"\n obj0 = %p class = %@ \n", array1[0], [array1[0] class]); NSLog(@"\n obj0 = %p class = %@ \n", array2[0], [array2[0] class]); NSLog(@"\n obj0 = %p class = %@ \n", array3[0], [array3[0] class]); NSLog (@ "\ n \ n = = = = = = = = element is mutableString = = = = = = = ="); NSLog(@"\n obj0 = %p class = %@ \n", array1[1], [array1[1] class]); NSLog(@"\n obj0 = %p class = %@ \n", array2[1], [array2[1] class]); NSLog(@"\n obj0 = %p class = %@ \n", array3[1], [array3[1] class]);Copy the code

View the output

2021-05-09 11:14:50.710409+0800 AlgorithmDemo[12261:67019] array1 = 0x1006B9e40 class = __NSArrayI (line1) array2 = 0x1006Ba180 Class = __NSArrayM (line1) array3 = 0x1006B7410 class = __NSArrayI (line1) ======== The element is String ======== obj0 = 0x100008220 class = __NSCFConstantString (line1) obj0 = 0x100008220 class = __NSCFConstantString (line1) obj0 = 0x1006B6D20 class = __NSCFString (line1) ======== The element is mutableString ======== obj0 = 0x1006B9CB0 class = __NSCFString (line1) obj0 = 0x1006ba0e0 class = __NSCFString (line1) obj0 = 0x1006b70e0 class = __NSCFString (line1)Copy the code

From the output, it is obvious that we come to the following conclusion

  • After an Array is archived and unarchived, new Array objects are generated
  • Immutable elements in an Array object are deeply copied
  • The mutable elements in the Array object are deeply copied

From this, we can draw the following conclusion

  • Just make a deep copy of an NSArray object, which we can do with mutableCopy
  • Only deep Copy NSMutableArray objects, either Copy or mutableCopy
  • Deep copies of Array objects and internal elements can be solved by archiving

3. Rewrite thecopyWithZone mutableCopyWithZoneDeep copy custom objects in the way

Let’s test that out by writing a Person class

//
//  Person.h
//  AlgorithmDemo
//
//  Created by Ternence on 2021/5/9.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, copy) NSString *nickname;

@end
Copy the code

The test code is as follows

Person *person = [[Person alloc] init]; Nickname = @" code code "; NSMutableArray *array1 = [NSMutableArray arrayWithObjects:person, nil]; NSArray *array2 = [array1 copy]; NSMutableArray *array3 = [array1 mutableCopy]; NSLog(@"\n array1 = %p class = %@", array1, [array1 class]); NSLog(@"\n array2 = %p class = %@", array2, [array2 class]); NSLog(@"\n array3 = %p class = %@", array3, [array3 class]); NSLog(@"\n\n======== elements in array ======== "); NSLog(@"\n array1[0] = %p class = %@", array1[0], [array1[0] class]); NSLog(@"\n array2[0] = %p class = %@", array2[0], [array2[0] class]); NSLog(@"\n array3[0] = %p class = %@", array3[0], [array3[0] class]);Copy the code

View the output

AlgorithmDemo[17319:89117] array1 = 0x102A04450 class = __NSArrayM array2 = 0x102A04550 Class = __NSSingleObjectArrayI array3 = 0x102A04570 class = __NSArrayM ======== elements in array ======== array1[0] = 0x102a042C0 class = Person array2[0] = 0x102a042c0 class = Person array3[0] = 0x102a042c0 class = PersonCopy the code

We find that the array object has been deeply copied, but the elements in the array object are still shallowly copied

Did we not override methods when we defined the Person class? Let’s change the code for the Person class and copy the elements in NSMutableArray

! In the copyWithZone mutableCopyWithZone method, we should copy the property as well

//
//  Person.m
//  AlgorithmDemo
//
//  Created by Ternence on 2021/5/9.
//

#import "Person.h"

@interface Person ()<NSCopying, NSMutableCopying, NSCoding>

@end

@implementation Person

- (id)copyWithZone:(NSZone *)zone {
    Person *person = [Person allocWithZone:zone];
    person.nickname = [self.nickname copy];
    return person;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    Person *person = [Person allocWithZone:zone];
    person.nickname = [self.nickname mutableCopy];
    return person;
}

@end
Copy the code

The test code

Person *person = [[Person alloc] init]; Nickname = @" code code "; NSMutableArray *array1 = [NSMutableArray arrayWithObjects:person, nil]; NSArray *array2 = [array1 copy]; NSMutableArray *array3 = [array1 mutableCopy]; NSMutableArray *array4 = [[NSMutableArray alloc] initWithArray:array1 copyItems:true]; NSMutableArray *array5 = [[NSMutableArray alloc] initWithObjects:[array1[0] copy], nil]; NSMutableArray *array6 = [[NSMutableArray alloc] initWithObjects:[array1[0] mutableCopy], nil]; NSLog(@"\n array1 = %p class = %@", array1, [array1 class]); NSLog(@"\n array2 = %p class = %@", array2, [array2 class]); NSLog(@"\n array3 = %p class = %@", array3, [array3 class]); NSLog(@"\n array4 = %p class = %@", array4, [array4 class]); NSLog(@"\n array5 = %p class = %@", array5, [array5 class]); NSLog(@"\n array6 = %p class = %@", array6, [array6 class]); NSLog(@"\n\n======== elements in array ========"); Person *orgArrayObj = (Person *)array1[0]; Person *newArrayObj2 = (Person *)array2[0]; Person *newArrayObj3 = (Person *)array3[0]; Person *newArrayObj4 = (Person *)array4[0]; Person *newArrayObj5 = (Person *)array5[0]; Person *newArrayObj6 = (Person *)array6[0]; NSLog(@"\n array1[0] = %p nickname = %p", orgArrayObj, orgArrayObj.nickname); NSLog(@"\n array2[0] = %p nickname = %p", newArrayObj2, newArrayObj2.nickname); NSLog(@"\n array3[0] = %p nickname = %p", newArrayObj3, newArrayObj3.nickname); NSLog(@"\n array4[0] = %p nickname = %p", newArrayObj4, newArrayObj4.nickname); NSLog(@"\n array5[0] = %p nickname = %p", newArrayObj5, newArrayObj5.nickname); NSLog(@"\n array6[0] = %p nickname = %p", newArrayObj6, newArrayObj6.nickname);Copy the code

Continue to view the print

2021-05-10 11:18:25.020830+0800 AlgorithmDemo[98320:429537] array1 = 0x10041a790 class = __NSArrayM array2 = 0x100419b60  class = __NSSingleObjectArrayI array3 = 0x10041a880 class = __NSArrayM array4 = 0x10041a9f0 class = __NSArrayM array5 = 0x10041Aa20 Class = __NSArrayM Array6 = 0x10041AC70 Class = __NSArrayM ======== Elements in array ======== Array1 [0] = 0x10041a340 nickname = 0x1000083a0 array2[0] = 0x10041a340 nickname = 0x1000083a0 array3[0] = 0x10041a340 nickname = 0x1000083a0 array4[0] = 0x100417660 nickname = 0x1000083a0 array5[0] = 0x100415370 nickname = 0x1000083a0 array6[0] = 0x100412300 nickname = 0x10041ad20Copy the code

Let’s summarize the custom objects for overwriting copyWithZone: and mutableCopyWithZone: according to the print summary

  • [array copy],[array mutableCopy] Only array objects are deeply copied, elements are shallowly copied
  • initWithArray:array1 copyItems:Generates a newarray, and the elements in the arraypersonIt’s a deep copy, butpersonThe property of is still shallow-copied.personisNSStringObject,copyItemsCall iscopyWithZone.[NSString copy]Shallow copy)
  • By going through array, rightpersonCopy separately, which is calledpersonthecopyWithZoneIn which case NSArray is a deep copy, an element in NSArraypersonIt’s a deep copy,personDepending on the type of the property parameter (NSString shallow copy, NSMutableString deep copy)
  • By going through array, rightperson, respectively,mutable copyTo callpersonthemutableCopyWithZoneIn this case, NSArray is a deep copy, the elements in NSArray are deep copies, and the elements’ attribute parameters are also deep copies

At this point, we know that to make a deep copy of a custom object, the solution is to rewrite copyWithZone, mutableCopyWithZone, and call the corresponding method

####4. Make a deep copy of the custom object as an archive and change the Person class first

//
//  Person.m
//  AlgorithmDemo
//
//  Created by Ternence on 2021/5/9.
//

#import "Person.h"

@interface Person ()<NSCopying, NSMutableCopying, NSCoding>

@end

@implementation Person

- (instancetype)initWithCoder:(NSCoder *)coder {
    self.nickname = [coder decodeObjectForKey:@"nickname"];
    return  self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.nickname forKey:@"nickname"];
}

@end

Copy the code

Rewrite the test code

Person *person = [[Person alloc] init]; Nickname = @" code code "; NSMutableArray *array1 = [NSMutableArray arrayWithObjects:person, nil]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array1]; NSMutableArray *array2 = [NSKeyedUnarchiver unarchiveObjectWithData:data]; NSLog(@"\n array1 = %p class = %@", array1, [array1 class]); NSLog(@"\n array2 = %p class = %@", array2, [array2 class]); NSLog(@"\n\n======== elements in array ========"); Person *orgArrayObj = (Person *)array1[0]; Person *newArrayObj2 = (Person *)array2[0]; NSLog(@"\n array1[0] = %p nickname = %p", orgArrayObj, orgArrayObj.nickname); NSLog(@"\n array2[0] = %p nickname = %p", newArrayObj2, newArrayObj2.nickname);Copy the code

Take another look at the print

2021-05-10 11:41:52.420699+0800 AlgorithmDemo[2252:455650] array1 = 0x103B04e50 class = __NSArrayM array2 = 0x103b06f30 Class = __NSArrayM ======== Elements in the array ======== array1[0] = 0x10061dCC0 nickname = 0x1000083A0 Array2 [0] = 0x103b05860 nickname = 0x103b06120Copy the code

It is clear that the array object is deep-copied, the custom object person in the array is deep-copied, and the nickname of the custom object person is deep-copied

Here’s a year-end summary of Array’s copy:

  • copy:NSArray objectIs a shallow copy, butNSMutableArray objectIs a deep copy
  • mutableCopy: Always a deep copy
  • [Array copy], [Array mutableCopy]Because you only copy the Array itself, rightElements in an ArrayIs a shallow copy
  • To make a deep copy of an Array’s elements, essentially all elements are deep-copied
  • initWithArray:array1 copyItems:Generates a newarray.copyItems:trueIt’s just calling Array’scopyWithZoneMethod, the elements in the Array are shallow copies
  • throughBelong to the solution fileThe way can be achieved onarray ,The person element in the array,Person property nicknameDeep copy