查看输出
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
! 此处的copyWithZone
mutableCopyWithZone
方法里,我们应该对属性也进行copy
// // 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
测试代码
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]; 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======== 数组内元素 ========"); 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);
继续查看打印结果
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 ======== 数组内元素 ======== 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 = 0x10041ad20
我们再根据打印归纳总结一下
对于重写copyWithZone:
、mutableCopyWithZone:
的自定义对象
[array copy]
、[array mutableCopy]
只深拷贝了array对象,元素是浅拷贝
initWithArray:array1 copyItems:
生成了新的array
,且array内元素person
是深拷贝,但person
的属性仍然是浅拷贝(注:此处属性浅拷贝是因为:person
是NSString
对象,copyItems
调用的是copyWithZone
,[NSString copy]
是浅拷贝)
- 通过遍历array,对
person
分别copy, 会调用person
的copyWithZone
,此时NSArray是深拷贝,NSArray内元素person
是深拷贝,person
的属性参数是否深拷贝,取决于属性参数的类型(NSString浅拷贝, NSMutableString深拷贝)
- 通过遍历array,对
person
分别mutable copy
,会调用person
的mutableCopyWithZone
,此时NSArray 是深拷贝,NSArray内元素是深拷贝,元素的属性参数也是深拷贝
此时我们知道了,要对自定义对象进行深拷贝,解决方案是重写copyWithZone
、mutableCopyWithZone
,调用对应的方法即可
4. 用归档的方式深拷贝自定义对象
先改一下person类
// // 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
再改写测试代码
Person *person = [[Person alloc] init]; person.nickname = @"码代码的小马"; 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======== 数组内元素 ========"); 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);
再耐心查看一下打印
2021-05-10 11:41:52.420699+0800 AlgorithmDemo[2252:455650] array1 = 0x103b04e50 class = __NSArrayM array2 = 0x103b06f30 class = __NSArrayM ======== 数组内元素 ======== array1[0] = 0x10061dcc0 nickname = 0x1000083a0 array2[0] = 0x103b05860 nickname = 0x103b06120
很明显,array对象
深拷贝了,array内的自定义对象person
深拷贝了,自定义对象person
的nickname
也深拷贝了
我们来对Array的拷贝做个年终总结:
copy
:对NSArray对象
是浅拷贝,可NSMutableArray对象
是深拷贝
mutableCopy
:始终是深拷贝
[Array copy]、[Array mutableCopy]
因为只对Array对象本身做拷贝操作,对Array内的元素
是浅拷贝
- 要实现Array内元素的深拷贝,本质是元素全都进行深拷贝操作
initWithArray:array1 copyItems:
生成了新的array
,copyItems:true
只是调用了Array的copyWithZone
方法,Array内元素是浅拷贝
- 通过
归解档
的方式,可以实现对array
、array 内元素person
、person属性nickname
深拷贝