- 由上篇我们知道:
- copy: 对NSArray是浅拷贝,NSMutableArray是深拷贝
- mutableCopy: 始终是深拷贝
- 无论深浅拷贝,集合对象内元素都是浅拷贝
- 本篇主要探索
- 实现NSArray内元素的拷贝
通过本文你将知道
- 深拷贝NSArray
- 深拷贝NSArray内元素Person
- 深拷贝NSArray内元素Person的属性nickname
本文代码较多,建议一步步耐心跟着代码排查,会有不少收货
探索过程
1. 系统Api
我们发现系统系统了方法- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag
其中copyItems:(BOOL)flag
表示是否拷贝元素,我们先代码测试一下
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======== 元素是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======== 元素是mutableString ========"); NSLog(@"\n obj0 = %p class = %@ \n", array1[1], [array1[1] class]); NSLog(@"\n obj0 = %p class = %@ \n", array2[1], [array2[1] class]);
查看输出(为了下文对比,我对输出做了line标记)
2021-05-09 10:59:16.343163+0800 AlgorithmDemo[9904:51756] array1 = 0x100607650 class = __NSArrayI (line1) array2 = 0x1006074a0 class = __NSArrayM (line2) ======== 元素是String ======== obj0 = 0x100008220 class = __NSCFConstantString (line3) obj0 = 0x100008220 class = __NSCFConstantString (line4) ======== 元素是mutableString ======== obj0 = 0x100606330 class = __NSCFString (line5) obj0 = 0x100605430 class = __NSCFString (line6)
根据输出我们对得出系统initWithArray : copyItems :
方法如下结论
该方法对NSArray对象是深拷贝(严格意义来说此处不能称为拷贝,是生成新对象)(line1 line2)
- 当数组内元素为不可变对象时,该方法对元素执行浅拷贝
(line3 line4)
- 当数组内元素为可变对象时,该方法对元素执行深拷贝
(line4 line5)
由此我们知道,当我们想深拷贝NSArray及其内部的元素时,用系统方法- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag
是不行的
2. 归档
如果我们对Array执行归档再解档,结果会是什么样的呢,我们代码测试一下
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======== 元素是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======== 元素是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]);
查看输出
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) ======== 元素是String ======== obj0 = 0x100008220 class = __NSCFConstantString (line1) obj0 = 0x100008220 class = __NSCFConstantString (line1) obj0 = 0x1006b6d20 class = __NSCFString (line1) ======== 元素是mutableString ======== obj0 = 0x1006b9cb0 class = __NSCFString (line1) obj0 = 0x1006ba0e0 class = __NSCFString (line1) obj0 = 0x1006b70e0 class = __NSCFString (line1)
根据输出,我们很明显得出如下结论
- 对Array归档并解档后,会生成新的Array对象
- Array对象内的不可变元素进行了深拷贝
- Array对象内的可变元素进行了深拷贝
由此,我们得出对如下总结
- 只深拷贝NSArray对象,我们用mutableCopy就可以
- 只深拷贝NSMutableArray对象,我们用Copy或mutableCopy都可以
- 深拷贝Array对象及内部元素,我们可以通过归档的方法解决
3. 重写copyWithZone
mutableCopyWithZone
的方式深拷贝自定义对象
我们写一个person类测试一下
// // Person.h // AlgorithmDemo // // Created by Ternence on 2021/5/9. // #import <Foundation/Foundation.h> @interface Person : NSObject @property (nonatomic, copy) NSString *nickname; @end
测试代码如下
Person *person = [[Person alloc] init]; person.nickname = @"码代码的小马"; 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======== 数组内元素 ======== "); 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]);