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


相关文章
|
6月前
|
JavaScript 前端开发 API
【JavaScript】<JS内建对象>JavaScript内建对象-Array对象
【1月更文挑战第17天】【JavaScript】<JS内建对象>JavaScript内建对象-Array对象
|
6月前
|
iOS开发 UED
实现一个自定义的iOS动画效果
【4月更文挑战第9天】本文将详细介绍如何在iOS平台上实现一个自定义的动画效果。我们将通过使用Core Animation框架来实现这个动画效果,并展示如何在不同的场景中使用它。文章的目标是帮助读者理解如何使用Core Animation框架来创建自定义动画,并提供一个简单的示例代码。
52 1
|
15天前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户点击按钮时,按钮将从圆形变为椭圆形,颜色从蓝色渐变到绿色;释放按钮时,动画以相反方式恢复。通过UIView的动画方法和弹簧动画效果,实现平滑自然的过渡。
31 1
|
24天前
|
Swift iOS开发 UED
如何使用Swift和UIKit在iOS应用中实现自定义按钮动画
【10月更文挑战第18天】本文通过一个具体案例,介绍如何使用Swift和UIKit在iOS应用中实现自定义按钮动画。当用户按下按钮时,按钮将从圆形变为椭圆形并从蓝色渐变为绿色;释放按钮时,动画恢复原状。通过UIView的动画方法和弹簧动画效果,实现平滑自然的动画过渡。
46 5
|
1月前
|
Swift iOS开发 UED
实现一个自定义的iOS动画效果
本文介绍如何使用Swift和UIKit在iOS应用中实现一个自定义按钮动画,当按钮被点击时,其颜色从蓝色渐变为绿色,形状从圆形变为椭圆形,释放后恢复原状。通过UIView动画方法实现这一效果,代码示例展示了动画的平滑过渡和状态切换,有助于提升应用的视觉体验和用户交互。
49 1
|
1月前
|
存储 JavaScript 前端开发
JavaScript Array(数组) 对象
JavaScript Array(数组) 对象
27 3
|
2月前
|
iOS开发 UED 开发者
iOS 手势中cancelsTouchesInView delaysTouchesBegan delaysTouchesEnded 三种属性的使用
iOS 手势中cancelsTouchesInView delaysTouchesBegan delaysTouchesEnded 三种属性的使用
91 9
|
2月前
|
Swift iOS开发 UED
揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【9月更文挑战第5天】本文通过具体案例介绍如何在iOS应用中使用Swift与UIKit实现自定义按钮动画,当用户点击按钮时,按钮将从圆形变为椭圆形并从蓝色渐变到绿色,释放后恢复原状。文中详细展示了代码实现过程及动画平滑过渡的技巧,帮助读者提升应用的视觉体验与特色。
61 11
|
3月前
|
Swift iOS开发 UED
【绝妙创意】颠覆你的视觉体验!揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【8月更文挑战第13天】本文通过一个具体案例,介绍如何使用Swift与UIKit在iOS应用中创建独特的按钮动画效果。当按钮被按下时,其形状从圆形变化为椭圆形,颜色则从蓝色渐变为绿色;释放后,动画反向恢复原状。利用UIView动画方法及弹簧动画效果,实现了平滑自然的过渡。通过调整参数,开发者可以进一步优化动画体验,增强应用的互动性和视觉吸引力。
51 7
|
3月前
|
Swift iOS开发
iOS开发-属性的内存管理
【8月更文挑战第12天】在iOS开发中,属性的内存管理至关重要,直接影响应用性能与稳定性。主要策略包括:`strong`(强引用),不维持对象生命期,可用于解除循环引用;`assign`(赋值),适用于基本数据类型及非指针对象属性;`copy`,复制对象而非引用,确保对象不变性。iOS采用引用计数管理内存,ARC(自动引用计数)自动处理引用增减,简化开发。为避免循环引用,可利用弱引用或Swift中的`[weak self]`。最佳实践包括:选择恰当的内存管理策略、减少不必要的强引用、及时释放不再使用的对象、注意block内存管理,并使用Xcode工具进行内存分析。