zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

iOS - 如何深拷贝Array内元素、自定义对象、及自定义对象的属性(下)

ios属性对象 如何 自定义 元素 Array 拷贝
2023-09-27 14:25:58 时间

查看输出

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 

 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 

 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深拷贝



iOS对象属性详解 retain,strong, copy,weak,assign,readonly, readwrite, unsafe_unretained 下面来分别讲讲各自的作用和区别:
产品百科 | RTC iOS SDK 如何设置视频属性 本文将为您介绍如何设置视频流规格、视频流类型和视频属性。阅读本文后,你可以根据实际业务需求设置视频属性,以达到更好的产品体验。