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

简介: 关于深拷贝、浅拷贝,请看上篇iOS - 深拷贝、浅拷贝探索验证

查看输出

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


! 此处的copyWithZonemutableCopyWithZone方法里,我们应该对属性也进行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的属性仍然是浅拷贝(注:此处属性浅拷贝是因为:personNSString对象, copyItems 调用的是copyWithZone, [NSString copy]是浅拷贝)


  • 通过遍历array,对person分别copy, 会调用personcopyWithZone,此时NSArray是深拷贝,NSArray内元素person是深拷贝, person的属性参数是否深拷贝,取决于属性参数的类型(NSString浅拷贝, NSMutableString深拷贝)


  • 通过遍历array,对person分别mutable copy,会调用personmutableCopyWithZone,此时NSArray 是深拷贝,NSArray内元素是深拷贝,元素的属性参数也是深拷贝


此时我们知道了,要对自定义对象进行深拷贝,解决方案是重写copyWithZonemutableCopyWithZone,调用对应的方法即可


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深拷贝了,自定义对象personnickname也深拷贝了


我们来对Array的拷贝做个年终总结:


  • copy:对NSArray对象是浅拷贝,可NSMutableArray对象是深拷贝


  • mutableCopy:始终是深拷贝


  • [Array copy]、[Array mutableCopy]因为只对Array对象本身做拷贝操作,对Array内的元素是浅拷贝


  • 要实现Array内元素的深拷贝,本质是元素全都进行深拷贝操作


  • initWithArray:array1 copyItems:生成了新的arraycopyItems:true只是调用了Array的copyWithZone方法,Array内元素是浅拷贝


  • 通过归解档的方式,可以实现对arrayarray 内元素personperson属性nickname深拷贝


相关文章
|
JavaScript 前端开发 API
【JavaScript】<JS内建对象>JavaScript内建对象-Array对象
【1月更文挑战第17天】【JavaScript】<JS内建对象>JavaScript内建对象-Array对象
|
10月前
|
移动开发 运维 供应链
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
array.some()可以用来权限检查、表单验证、库存管理、内容审查和数据处理等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
10月前
|
供应链 JavaScript 前端开发
通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
array.every()可以用来数据验证、权限检查、一致性检查等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
10月前
|
Web App开发 存储 前端开发
别再用双层遍历循环来做新旧数组对比,寻找新增元素了!使用array.includes和Set来提升代码可读性
这类问题的重点在于能不能突破基础思路,突破基础思路是从程序员入门变成中级甚至高级的第一步,如果所有需求都通过最基础的业务逻辑来做,是得不到成长的。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
存储 JavaScript 前端开发
JavaScript Array(数组) 对象
JavaScript Array(数组) 对象
137 3
|
iOS开发 UED 开发者
iOS 手势中cancelsTouchesInView delaysTouchesBegan delaysTouchesEnded 三种属性的使用
iOS 手势中cancelsTouchesInView delaysTouchesBegan delaysTouchesEnded 三种属性的使用
548 10
|
Swift iOS开发
iOS开发-属性的内存管理
【8月更文挑战第12天】在iOS开发中,属性的内存管理至关重要,直接影响应用性能与稳定性。主要策略包括:`strong`(强引用),不维持对象生命期,可用于解除循环引用;`assign`(赋值),适用于基本数据类型及非指针对象属性;`copy`,复制对象而非引用,确保对象不变性。iOS采用引用计数管理内存,ARC(自动引用计数)自动处理引用增减,简化开发。为避免循环引用,可利用弱引用或Swift中的`[weak self]`。最佳实践包括:选择恰当的内存管理策略、减少不必要的强引用、及时释放不再使用的对象、注意block内存管理,并使用Xcode工具进行内存分析。
184 1
|
前端开发 iOS开发
input框设置placeholder属性在iOS中显示不完整
input框设置placeholder属性在iOS中显示不完整
233 1
|
前端开发
let array = [{id:‘001‘,name:‘小新‘,age:5},{ id:‘002‘,name:‘小葵‘]这样数据如何遍历,拿到其中一个值,数组中装对象如何获取其中一个固定的值
let array = [{id:‘001‘,name:‘小新‘,age:5},{ id:‘002‘,name:‘小葵‘]这样数据如何遍历,拿到其中一个值,数组中装对象如何获取其中一个固定的值
ArrayList集合常用方法,.set可以用来生成图片和赋值命名,array.remove(1),array.set(1,“xxxx”)可以修改指定位置,array.size可以获取元素的个数
ArrayList集合常用方法,.set可以用来生成图片和赋值命名,array.remove(1),array.set(1,“xxxx”)可以修改指定位置,array.size可以获取元素的个数

热门文章

最新文章

  • 1
    PHP 数组查找:为什么 `isset()` 比 `in_array()` 快得多?
    192
  • 2
    Java 中数组Array和列表List的转换
    788
  • 3
    JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
    645
  • 4
    通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式、聚合统计、处理树结构数据和性能优化,reduce()的使用详解(附实际应用代码)
    1404
  • 5
    通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
    505
  • 6
    通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
    316
  • 7
    多维数组操作,不要再用遍历循环foreach了!来试试数组展平的小妙招!array.flat()用法与array.flatMap() 用法及二者差异详解
    204
  • 8
    别再用双层遍历循环来做新旧数组对比,寻找新增元素了!使用array.includes和Set来提升代码可读性
    229
  • 9
    Array.forEach实战详解:简化循环与增强代码可读性;Array.forEach怎么用;面对大量数据时怎么提高Array.forEach的性能
    145
  • 10
    深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解
    605