集合对象与非集合对象所遵循的规则基本上是一样的,唯一差别:
集合对象的深复制并不是严格意义上的深复制,而是单层深复制。
单层深复制:对集合对象来说,深复制时只是将第一层对象进行了深复制,内部的对象仍然是浅复制。
下面一步一步验证得出的结论:
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依然是浅拷贝。
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来说,依然是浅拷贝。
总结:
针对数组来说:深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];
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.有任何问题欢迎留言评论。