For deep copy and shallow copy, see iOS – Deep copy and Shallow copy Exploration and Verification
- 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
- 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
mutableCopyWithZone
Deep 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 copiedinitWithArray:array1 copyItems:
Generates a newarray
, and the elements in the arrayperson
It’s a deep copy, butperson
The property of is still shallow-copied.person
isNSString
Object,copyItems
Call iscopyWithZone
.[NSString copy]
Shallow copy)- By going through array, right
person
Copy separately, which is calledperson
thecopyWithZone
In which case NSArray is a deep copy, an element in NSArrayperson
It’s a deep copy,person
Depending on the type of the property parameter (NSString shallow copy, NSMutableString deep copy) - By going through array, right
person
, respectively,mutable copy
To callperson
themutableCopyWithZone
In 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 object
Is a shallow copy, butNSMutableArray object
Is a deep copymutableCopy
: Always a deep copy[Array copy], [Array mutableCopy]
Because you only copy the Array itself, rightElements in an Array
Is 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:true
It’s just calling Array’scopyWithZone
Method, the elements in the Array are shallow copies- through
Belong to the solution file
The way can be achieved onarray
,The person element in the array
,Person property nickname
Deep copy