关于深拷贝、浅拷贝,请看上篇iOS – 深拷贝、浅拷贝探索验证
- 由上篇我们知道:
- 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. 如果Array对象内元素是自定义对象呢
我们写一个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]);
复制代码
查看输出
2021-05-09 11:33:47.241685+0800 AlgorithmDemo[17319:89117]
array1 = 0x102a04450 class = __NSArrayM
array2 = 0x102a04550 class = __NSSingleObjectArrayI
array3 = 0x102a04570 class = __NSArrayM
======== 数组内元素 ========
array1[0] = 0x102a042c0 class = Person
array2[0] = 0x102a042c0 class = Person
array3[0] = 0x102a042c0 class = Person
复制代码
我们发现数组对象已经被深拷贝,但数组对象内的元素还是浅拷贝
是不是我们在定义Person类的时候没有重写方法呢? 我们把改一下Person类的代码,并对NSMutableArray内元素进行copy
//
// Person.m
// AlgorithmDemo
//
// Created by Ternence on 2021/5/9.
//
#import "Person.h"
@interface Person ()<NSCopying, NSMutableCopying>
@end
@implementation Person
- (id)copyWithZone:(NSZone *)zone {
Person *person = [Person allocWithZone:zone];
person.nickname = self.nickname;
return person;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
Person *person = [Person allocWithZone:zone];
person.nickname = self.nickname;
return self;
}
@end
复制代码
测试代码
Person *person = [[Person alloc] init];
person.nickname = @"码代码的小马";
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];
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\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]);
NSLog(@"\n\n======== 数组内元素1 ========");
Person *orgArrayObj = (Person *)array1[0];
Person *newArrayObj = (Person *)array4[0];
Person *newArrayObj5 = (Person *)array5[0];
NSLog(@"\n array1[0] = %p class = %@ nickname = %p", orgArrayObj, [orgArrayObj class], orgArrayObj.nickname);
NSLog(@"\n array4[0] = %p class = %@ nickname = %p", newArrayObj, [newArrayObj class], newArrayObj.nickname);
NSLog(@"\n array5[0] = %p class = %@ nickname = %p", newArrayObj5, [newArrayObj5 class], newArrayObj5.nickname);
复制代码
继续查看打印结果
2021-05-09 12:10:28.436585+0800 AlgorithmDemo[23153:133313]
array1 = 0x1032043c0 class = __NSArrayM
array2 = 0x1032044f0 class = __NSSingleObjectArrayI
array3 = 0x103204510 class = __NSArrayM
array4 = 0x103204690 class = __NSArrayM
array5 = 0x1032046e0 class = __NSArrayM
======== 数组内元素 ========
array1[0] = 0x103204880 class = Person
array2[0] = 0x103204880 class = Person
array3[0] = 0x103204880 class = Person
======== 数组内元素1 ========
array1[0] = 0x103204880 class = Person nickname = 0x1000083a0
array4[0] = 0x103204680 class = Person nickname = 0x1000083a0
array5[0] = 0x1032046d0 class = Person nickname = 0x1000083a0
复制代码
我们再根据打印归纳总结一下
对于重写copyWithZone:、mutableCopyWithZone:的自定义对象
[array copy]、[array mutableCopy]只深拷贝了array对象,元素是浅拷贝initWithArray:array1 copyItems:生成了新的array,且array内元素person是深拷贝,但person的属性仍然是浅拷贝- 我们分别用遍历copy array内自定义对象
person生成新array的方法,自定义倒是深拷贝了,但自定义对象person的属性nickname仍然是浅拷贝
看到此处你可能会很绝望,我也很绝望…到底怎么样才能深拷贝array对象及其元素呢?
我们再试试归档的方法
先改一下person类
//
// 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;
return person;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
Person *person = [Person allocWithZone:zone];
person.nickname = self.nickname;
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
self.nickname = [coder decodeObjectForKey:@"nickname"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.nickname forKey:@"nickname"];
}
@end
复制代码
再改写测试代码
Person *person = [[Person alloc] init];
person.nickname = @"码代码的小马";
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];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array1];
NSMutableArray *array6 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
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\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]);
NSLog(@"\n\n======== 数组内元素1 ========");
Person *orgArrayObj = (Person *)array1[0];
Person *newArrayObj = (Person *)array4[0];
Person *newArrayObj5 = (Person *)array5[0];
Person *newArrayObj6 = (Person *)array6[0];
NSLog(@"\n array1[0] = %p class = %@ nickname = %p", orgArrayObj, [orgArrayObj class], orgArrayObj.nickname);
NSLog(@"\n array4[0] = %p class = %@ nickname = %p", newArrayObj, [newArrayObj class], newArrayObj.nickname);
NSLog(@"\n array5[0] = %p class = %@ nickname = %p", newArrayObj5, [newArrayObj5 class], newArrayObj5.nickname);
NSLog(@"\n array6[0] = %p class = %@ nickname = %p", newArrayObj6, [newArrayObj6 class], newArrayObj6.nickname);
复制代码
再耐心查看一下打印
2021-05-09 12:15:28.206176+0800 AlgorithmDemo[23739:137444]
array1 = 0x10054bf80 class = __NSArrayM
array2 = 0x10053f290 class = __NSSingleObjectArrayI
array3 = 0x10054c0b0 class = __NSArrayM
array4 = 0x10054c220 class = __NSArrayM
array5 = 0x10054c250 class = __NSArrayM
======== 数组内元素 ========
array1[0] = 0x10054b890 class = Person
array2[0] = 0x10054b890 class = Person
array3[0] = 0x10054b890 class = Person
======== 数组内元素1 ========
array1[0] = 0x10054b890 class = Person nickname = 0x1000083a0
array4[0] = 0x10053dc30 class = Person nickname = 0x1000083a0
array5[0] = 0x10053de20 class = Person nickname = 0x1000083a0
array6[0] = 0x10054d300 class = Person nickname = 0x100548f00
复制代码
是的,我们成功了,归解档后,array对象深拷贝了,array内的自定义对象person深拷贝了,自定义对象person的nickname也深拷贝了
我们来对Array的拷贝做个年终总结:
copy:对NSArray对象是浅拷贝,可NSMutableArray对象是深拷贝mutableCopy:始终是深拷贝copy、mutable对array内的元素是浅拷贝initWithArray:array1 copyItems:生成了新的array,且array内元素person是深拷贝,但person的属性nickname仍然是浅拷贝- 通过
归解档的方式,可以实现对array、array 内元素person、person属性nickname深拷贝























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)