iOS 集合的深Copy和浅Copy

集合对象与非集合对象所遵循的规则基本上是一样的,唯一差别:

集合对象的深复制并不是严格意义上的深复制,而是单层深复制。
单层深复制:对集合对象来说,深复制时只是将第一层对象进行了深复制,内部的对象仍然是浅复制。

下面一步一步验证得出的结论:

1.NSArray与NSMutableArray

1. 1声明一个Person的model

同时实现NSCopying与NSMutableCopying

@interface Person : NSObject <NSCopying, NSMutableCopying>
@property (nonatomic) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end

@implementation Person

- (id)copyWithZone:(NSZone *)zone {
    Person *person = [[self class] allocWithZone:zone];
    person.name = self.name;
    person.age = self.age;
    
    return person;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    Person *person = [[self class] allocWithZone:zone];
    person.name = self.name;
    person.age = self.age;
    
    return person;
}
@end

1.2.NSArray与NSMutableArray的Copy与mutableCopy

1.2.1对Person进行Copy与mutableCopy

Person *person = [[Person alloc] init];
person.name = @"张三";
person.age = 18;
    
Person * personCopy = [person copy];
Person * personMutableCopy = [person mutableCopy];
NSLog(@"person=%p,personCopy=%p,personMutableCopy=%p",person,personCopy,personMutableCopy);

person=0x600002f0a700
personCopy=0x600002f0ae60
personMutableCopy=0x600002f0a480

结论:当实现<NSCopying, NSMutableCopying>协议时,对model进行Copy与MutableCopy都是深拷贝。

1.2.2NSArray的Copy与MutableCopy

Person *person = [[Person alloc] init];
person.name = @"张三";
person.age = 18;
    
NSArray *personArray = [NSArray arrayWithObject:person];
    
id personArrayCopy = [personArray copy];
id personArrayMutableCopy = [personArray mutableCopy];
    
NSLog(@"personArray=%p,personArrayCopy=%p,personArrayMutableCopy=%p",personArray,personArrayCopy,personArrayMutableCopy);

personArray=0x600002d16340
personArrayCopy=0x600002d16340
personArrayMutableCopy=0x600002195680

结论:NSArray的copy是浅拷贝,mutableCopy是深拷贝。这个结果是针对数组而言,数组的里的model依然是浅拷贝。

model浅拷贝

1.2.3NSMutableArray的Copy与MutableCopy

Person *person = [[Person alloc] init];
person.name = @"张三";
person.age = 18;
    
NSMutableArray *personMutableArray = [NSMutableArray arrayWithObject:person];
id personMutableArrayCopy = [personMutableArray copy];
id personMutableArrayMutableCopy = [personMutableArray mutableCopy];
    
NSLog(@"personMutableArray=%p,personMutableArrayCopy=%p,personMutableArrayMutableCopy=%p",personMutableArray,personMutableArrayCopy,personMutableArrayMutableCopy);

personMutableArray=0x6000021687b0
personMutableArrayCopy=0x600002d016f0
personMutableArrayMutableCopy=0x600002168780

结论: NSMutableArray的Copy与MutableCopy都是深拷贝。但对数组里的model来说,依然是浅拷贝。

浅拷贝model

总结:
针对数组来说:深Copy和浅Copy并不是指model层级的拷贝。数组的内容是指针,而指针的内容的拷贝即所谓的深拷贝与浅拷贝。

集合深浅拷贝以及经常遇到的坑中有段话,我觉得非常有道理:
CL1:arr数组指针,如果只发生这层拷贝,则和非集合对象一样,是浅拷贝
CL2:arr数组指针指向的的内容,即存储的对象指针。发生本层拷贝,从非集合角度来说已经发生了内容拷贝,即深拷贝。但从集合角度来说,还是浅拷贝。
CL3:arr数组里面存储的指针指向的内容,如果发生本层拷贝,可以叫做集合的单层深拷贝。

小提醒:数组的指针到底是什么?
数组分配的一块连续的内存区域,只要拿到指向首个元素的指针,我们就能访问和操作数组里各个元素。

2.实现数组中model拷贝

2.1循环遍历数组,逐个Copy

Person *person = [[Person alloc] init];
person.name = @"张三";
person.age = 18;
    
NSMutableArray *personMutableArray = [NSMutableArray arrayWithObject:person];
NSMutableArray * personDeepModelMutableArray = [[NSMutableArray alloc] init];
[personMutableArray enumerateObjectsUsingBlock:^(Person * _Nonnull person, NSUInteger idx, BOOL * _Nonnull stop) {
    [personDeepModelMutableArray addObject:[person copy]];
}];

2.2 使用copyItems

Person *person = [[Person alloc] init];
person.name = @"张三";
person.age = 18;
    
NSMutableArray *personMutableArray = [NSMutableArray arrayWithObject:person];
NSMutableArray * personDeepModelMutableArray = [[NSMutableArray alloc] initWithArray:personMutableArray copyItems:YES];

3.数组的深拷贝与浅拷贝不是model拷贝,那有什么用呢?

抛去数组可变与不可变,单层深复制的深浅拷贝有什么用,或者在什么场景下解决什么问题?

3.1 NSArray

NSArray * array = [NSArray arrayWithObjects:person, nil];
NSArray * arrayNoCopy = array;
NSArray * arrayCopy = [array copy];

针对NSArray的copy与直接赋值有没有什么区别?
在arc下,赋值(__strong)与copy引用计数都会+1,两者已没什么区别。

NSMutableArray * arrayMutableCopy = [array mutableCopy];
NSMutableArray * array = [[NSMutableArray alloc] initWithArray:array];

mutableCopy会产生一个可变数组,与alloc一个可变数组效果是一样的。
对于NSArray的深拷贝:由于NSArray不会发生改变,即使发生了深拷贝,也是没有任何意义。

3.2 NSMutableArray

Person *person = [[Person alloc] init];
person.name = @"张三";
person.age = 18;
    
NSMutableArray * mutableArray = [NSMutableArray arrayWithObjects:person, nil];
id mutableArrayNoCopy = mutableArray;
id mutableArrayCopy = [mutableArray copy];
id mutableArrayMutableCopy = [mutableArray mutableCopy];

[mutableArray removeAllObjects];
NSMutableArray

1.NSMutableArray的copy与mutableCopy都是深拷贝,而copy产生的是不可变数组,直接赋值与mutableCopy还是可变数组。
2.如果直接赋值,原来数组的改变(如移除元素或增加元素)会导致赋值的数组也会发生改变;而使用了copy与mutableCopy则不会受原来数组的影响。而使用copy与mutableCopy则看需要的是可变还是不可变数组。
3.NSArray则不会存在这个问题,所以NSArray的直接赋值、copy、mutableCopy在深浅拷贝上没什么区别,因为NSArray是不可变的,有区别的也是返回的是可变还是不可变数组。

4.经典错误

NSArray * array = [NSArray array];
NSMutableArray * mutableArray = [array copy];

使用copy赋值给可变数组,而实际上mutableArray还是不可变数组,把NSArray当做NSMutableArray使用时,会导致找不到方法而发生崩溃。

NSMutableArray是继承自NSArray,按里氏替换原则:子类可以无缝替换父类,但父类不能够替换子类。

属性声明同理:

@property (nonatomic,copy) NSMutableArray *

无论是可变数组还是不可变数组,最后都是不可变数组,只要使用了可变数组的方法,必然崩溃。

总结:
1.集合的深浅拷贝并不是指集合中的model发生深浅拷贝,而是针对集合指针而言。
2.可变集合直接赋值与拷贝(copy、mutableCopy)的区别很大。不可变集合的深拷贝与浅拷贝意义是一样的,因为不可变集合不会发生改变。
3.不要使用copy赋值给可变集合,属性设置也是同理,会发生崩溃。
4.可变数组不能使用copy,不可变数组使用copy没有意义,所以建议集合使用strong。
5.有任何问题欢迎留言评论。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容