Deep copy
Shallow copy
copy
mutableCopy
Single copy
Interview question: 1) What is deep copy and what is shallow copy? 2) Is it deep copy or shallow copy for mutable objects? 3) Why use copy modifier for NSString attributes? Can you change it to strong? 4) @property (copy) NSMutableArray *array; What’s wrong with writing this way? 5) What is single-layer copy and how to implement multi-layer copy? 6) Why copy is used when modifying block attributes?
Deep copy and shallow copy
Shallow copy: A shallow copy is a copy of the memory address, so that the pointer to the target object and the pointer to the source object point to the same memory space. When the memory is destroyed, the Pointers to the memory must be defined again. Otherwise, the Pointers will become wild Pointers. Deep copy: In deep copy, object contents are copied, and the memory address is independently allocated. After the copy is complete, the two objects store the same value but have different memory addresses. The two objects do not interfere with each other.
【 Summary 】 Deep copy is content copy, shallow copy is pointer copy. The essential difference is:
- Whether to enable a new memory address.
- Whether reference counting of memory addresses is affected;
Copy and mutableCopy
You can create a copy of an object using the copy or mutableCopy methods.
Copy: NSCoppying protocol needs to be implemented. These create immutable copies (NSString, NSArray, NSDictionary); MutableCopy: NSMutableCopying must be implemented first. Create mutable copies (such as NSMutableString, NSMutableArray, NSMutableDictionary);
Single-layer and multi-layer copy
1. Copy and mutableCopy of normal objects
1) Immutable object copy
NSString *str = @"Immutable object";
NSString *copyStr = [str copy];
NSLog(@"STR =%@, address: %p",str, str);
NSLog(@"CopyStr =%@ address: %p",copyStr, copyStr); // Print: 2020-07-05 10:59:46.208267+0800 OCTestDemo[77626:1744180] STR = immutable object, address: 0x108704330 2020-07-05 10:59:46.208372+0800 OCTestDemo[77626:1744180] copyStr= Immutable object, address: 0x108704330 Copy is a shallow copy of an immutable object.Copy the code
2) Immutable object mutable object
NSString *str = @"Immutable object";
NSString *mtCopyStr = [str mutableCopy];
NSLog(@"STR =%@, address: %p",str, str);
NSLog(@MtCopyStr =%@, address: %p",mtCopyStr, mtCopyStr); // Print: 2020-07-05 11:01:20.982338+0800 OCTestDemo[77699:1746254] 0x10FA86330 2020-07-05 11:01:20.982470+0800 OCTestDemo[77699:1746254] mtCopyStr= immutable object, address: 0x600000257fa0 For immutable object mutableCopy, it is a deep copy.Copy the code
3) Mutable object copy
NSMutableString *str = [NSMutableString stringWithString:@"Mutable object"];
NSString *copyStr = [str copy];
NSLog(@"STR =%@, address: %p",str, str);
NSLog(@"CopyStr =%@ address: %p",copyStr, copyStr); // Print: 2020-07-05 11:04:04.408830+0800 OCTestDemo[77768:1748628] STR = variable object, address: 0x60000024C900 2020-07-05 11:04:04.408933+0800 OCTestDemo[77768:1748628] copyStr= Variable object, address: 0x6000002279A0 Copy mutable objects. It is a deep copy.Copy the code
4) Mutable object mutable object
NSMutableString *str = [NSMutableString stringWithString:@"Mutable object"];
NSString *mtCopyStr = [str mutableCopy];
NSLog(@"STR =%@, address: %p",str, str);
NSLog(@MtCopyStr =%@, address: %p",mtCopyStr, mtCopyStr); // Print: 2020-07-05 11:05:38.838961+0800 OCTestDemo[77828:1750661] 0x600000256200 2020-07-05 11:05:38.839065+0800 OCTestDemo[77828:1750661] mtCopyStr= variable object, address: 0x60000025e8d0 For mutable object mutableCopy, it's a deep copy.Copy the code
Copy and mutableCopy of the container class object
Animal *dog = [[Animal alloc]init];
Animal *cat = [[Animal alloc]init];
Animal *pig = [[Animal alloc]init];
Copy the code
1) Immutable container object copy
NSArray *arr = @[dog, cat, pig];
NSArray *copyArr = [arr copy];
NSLog(@Arr =%@, address: %p,arr, arr);
NSLog(@"CopyArr =%@, address: %p",copyArr, copyArr); OCTestDemo[77897:1754011] arr=("<Animal: 0x600000015fc0>"."<Animal: 0x600000015670>"."<Animal: 0x600000015220>"CopyArr =(0x6000004598F0 2020-07-05 11:10:12.325063+0800 OCTestDemo[77897:1754011]"<Animal: 0x600000015fc0>"."<Animal: 0x600000015670>"."<Animal: 0x600000015220>"), address: 0x6000004598f0 // Conclusion: Copy immutable container objects is a shallow copy and a single layer copy.Copy the code
2) immutable container object mutableCopy
NSArray *arr = @[dog, cat, pig];
NSArray *mtCopyArr = [arr mutableCopy];
NSLog(@Arr =%@, address: %p,arr, arr);
NSLog(@"MtCopyArr =%@, address: %p",mtCopyArr, mtCopyArr); 281808+0800 OCTestDemo[77952:1756412] arr="<Animal: 0x604000202810>"."<Animal: 0x6040000178c0>"."<Animal: 0x604000017c70>"OCTestDemo[77952:1756412] mtCopyArr=("<Animal: 0x604000202810>"."<Animal: 0x6040000178c0>"."<Animal: 0x604000017c70>"), address: 0x60400024D020 // Conclusion: For immutable container object mutableCopy, it is a deep copy and a single layer copy.Copy the code
3) Mutable container object copy
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *copyArr = [arr copy];
NSLog(@Arr =%@, address: %p,arr, arr);
NSLog(@"CopyArr =%@, address: %p",copyArr, copyArr); OCTestDemo[78006:1758411] arr=("<Animal: 0x60400001e990>"."<Animal: 0x60400001e400>"."<Animal: 0x60400001e390>"(0x60400024b040 2020-07-05 11:15:05.864007+0800 OCTestDemo[78006:1758411] copyArr=("<Animal: 0x60400001e990>"."<Animal: 0x60400001e400>"."<Animal: 0x60400001e390>"), address: 0x60400024AF50 // Conclusion: Copy mutable container objects is a deep copy and a single-layer copy.Copy the code
4) Mutable container object mutable container object
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *mtCopyArr = [arr mutableCopy];
NSLog(@Arr =%@, address: %p,arr, arr);
NSLog(@"MtCopyArr =%@, address: %p",mtCopyArr, mtCopyArr); OCTestDemo[78056:1760281] arr=("<Animal: 0x600000013270>"."<Animal: 0x600000012fb0>"."<Animal: 0x600000013b70>"0x6000004403C0 2020-07-05 11:16:56.869378+0800 OCTestDemo[78056:1760281] mtCopyArr=("<Animal: 0x600000013270>"."<Animal: 0x600000012fb0>"."<Animal: 0x600000013b70>"), address: 0x600000440480 // Conclusion: The mutable container object mutableCopy is a deep copy and a single layer copy.Copy the code
3. Implementation scheme of multi-layer copy
1)- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag;
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *deepCopyArr = [[NSArray alloc]initWithArray:arr copyItems:YES];
NSLog(@Arr =%@, address: %p,arr, arr);
NSLog(@"DeepCopyArr =%@, address: %p",deepCopyArr, deepCopyArr); OCTestDemo[78309:1769460] arr=("<Animal: 0x600000000df0>"."<Animal: 0x6000000006b0>"."<Animal: 0x600000000cd0>"OCTestDemo[78309:1769460] deepCopyArr=("<Animal: 0x600000000b70>"."<Animal: 0x600000000dc0>"."<Animal: 0x600000000d80>"), address: 0x6000002544f0 // Conclusion: Use initWithArray:copyItems: method to achieve the effect of multiple copies, but this is only a double copy, not a true multi-layer copy. / / note that the elements in the array need to implement NSCopying, NSMutableCopying protocol.Copy the code
2) Archiving solution method
NSMutableArray *arr = [NSMutableArray arrayWithArray:@[dog, cat, pig]];
NSArray *deepCopyArr = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arr]];
NSLog(@Arr =%@, address: %p,arr, arr);
NSLog(@"DeepCopyArr =%@, address: %p",deepCopyArr, deepCopyArr); // Print: 2020-07-05 11:38:08.175207+0800 OCTestDemo[78604:1779461] arr="<Animal: 0x60000000ab90>"."<Animal: 0x60000000ab70>"."<Animal: 0x600000010bf0>"OCTestDemo[78604:1779461] deepCopyArr=("<Animal: 0x600000010f70>"."<Animal: 0x600000010ef0>"."<Animal: 0x600000010f60>"), address: 0x60000044F600 // Conclusion: Using archive unfile method can achieve the effect of multi-layer copy. Note that the elements in the array need to implement the NSCoding protocol.Copy the code
conclusion
supplement
1, why use copy modifier for NSString attributes? Is it ok to use strong?
NSString, NSArray, NSDictionary, and so on often use the copy keyword because they have corresponding mutable types: NSMutableString, NSMutableArray, NSMutableDictionary;
The copy attribute expresses ownership similar to that of strong. However, the setting method does not keep the new value, but “copies” it. This property is often used to protect encapsulation when the attribute type is NSString, because the new value passed to the setting method might point to an instance of the NSMutableString class.
NSString, NSArray, and NSDictionary often use copy because they have mutable types: NSMutableString, NSMutableArray, and NSMutableDictionary, all of which may be assigned to each other, should be copied when setting the new property value to ensure that the string value in the object does not change unintentionally.
2. Why copy when modifying block properties?
Block use of copy is a “legacy” from MRC, where the block inside a method is on the stack and copy can be used to put it on the heap. It doesn’t matter whether you write in ARC: Copy or strong has the same effect on a block, but it doesn’t hurt to write copy and reminds us that the compiler automatically copies the block.
3,@property (copy) NSMutableArray *array;
What’s wrong with writing this way?
Two problems: 1. When adding, deleting and modifying elements in the array, the program will crash because it cannot find the corresponding method. Because copy is copying an immutable NSArray object; 2. Using atomic attributes can seriously affect performance;