一、深浅拷贝
1、 什么是深拷贝?
深拷贝是对内容的拷贝,复制内容,同时有新的指针指向该内存区域;
2、什么是浅拷贝?
浅拷贝只做指针复制,两个指针指向同一处内存空间;
3、对于拷贝,详细来说有四方面内容:
1、不可变对象的拷贝操作:immutableObjc -> copy
2、不可变对象的可变拷贝操作:immutableObjc -> mutableCopy
3、可变对象的拷贝操作:mutableObjc -> copy
4、可变对象的可变拷贝操作:mutableObjc -> mutableCopy
二、非集合对象的深浅拷贝(NSString、NSNumber...)
1、不可变对象的 copy 和 mutableCopy
NSString *string = @"string";
NSString *copyString = [string copy]; // 没有产生新对象
NSMutableString *mutCopyString = [string mutableCopy]; // 产生新对象
NSLog(@"\n string = %p\n copyString = %p\n mutCopyString = %p", string, copyString, mutCopyString);
打印结果:
结论:对不可变对象 copy 是浅拷贝,mutablecopy 是深拷贝;
2、可变对象的 copy 和 mutableCopy
NSMutableString *string = [NSMutableString stringWithString:@"mutString"];
NSString *copyString = [string copy]; // 产生新对象
NSMutableString *mutCopyString = [string mutableCopy]; // 产生新对象
NSLog(@"\n string = %p\n copyString = %p\n mutCopyString = %p", string, copyString, mutCopyString);
打印结果:
结论:对可变对象 copy 和 mutablecopy 都是深拷贝;
3、非集合对象的深浅拷贝:
- immutableObjc -> copy 浅拷贝
- immutableObjc -> mutableCopy 深拷贝
- mutableObjc -> copy 深拷贝
- mutableObjc -> mutableCopy 深拷贝
三、集合对象的深浅拷贝(NSArray、NSSet、NSDictionary)
1、集合的浅复制 (shallow copy)
集合的浅复制有非常多种方法。当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合。
现在让我们看一些浅复制的例子:
NSArray *shallowCopyArray = [someArray copyWithZone:nil];
NSSet *shallowCopySet = [NSSet mutableCopyWithZone:nil];
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];
2、集合的深复制 (deep copy)
方式一:用 initWithArray:copyItems: 将第二个参数设置为YES
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];
如果使用这种方法深复制,集合里的每个对象都会收到 copyWithZone: 消息。如果集合里的对象遵循 NSCopying 协议,那么对象就会被深复制到新的集合。如果对象没有遵循 NSCopying 协议,而尝试用这种方法进行深复制,会在运行时出错。copyWithZone: 这种拷贝方式只能够提供一层内存拷贝(one-level-deep copy),而非真正的深复制。
方式二:将集合进行归档(archive),然后解档(unarchive)
NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
3、集合的单层深复制 (one-level-deep copy)
什么是单层深复制呢?如果在多层数组中,对第一层进行内容拷贝,其它层进行指针拷贝,这种情况,即为单层深复制。苹果的官方文档
苹果认为这种复制不是真正的深复制,而是将其称为单层深复制(one-level-deep copy)。因此,有人对浅复制、单层深复制、深复制做了概念区分。
- 浅复制(shallow copy):在浅复制操作时,对于被复制对象的每一层都是指针复制。
- 单层深复制(one-level-deep copy):在深复制操作时,对于被复制对象,至少有一层是深复制。
- 完全复制(real-deep copy):在完全复制操作时,对于被复制对象的每一层都是对象复制。
1、不可变对象的 copy 和 mutableCopy
NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
NSArray *copyArray = [array copy];
NSMutableArray *mutCopyArray = [array mutableCopy];
NSLog(@"\narray - %p\ncopy - %p\nmutCopy - %p", array, copyArray, mutCopyArray);
打印结果:
结论:
- 查看内容,可以看到 copyArray 和 array 的地址是一样的,而 mutCopyArray 和 array 的地址是不同的。说明 copy 操作进行了指针拷贝,mutableCopy 进行了内容拷贝。
- 需要强调的是:此处的内容拷贝,仅仅是拷贝 array 这个对象,array 集合内部的元素仍然是指针拷贝。这和上面的非集合 immutable 对象的拷贝还是挺相似的,
2、可变对象的 copy 和 mutableCopy
NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];
NSArray *copyArray = [array copy];
NSMutableArray *mutCopyArray = [array mutableCopy];
NSLog(@"\narray - %p\ncopy - %p\nmutCopy - %p", array, copyArray, mutCopyArray);
查看结果:
结论:
- 根据打印结果可以看到 copyArray、mutCopyArray 和array 的内存地址都不一样,说明 copyArray、 mutCopyArray 都对 array 进行了内容拷贝。
- 在集合类对象中,对 immutable 对象进行 copy,是指针复制,mutableCopy 是内容复制;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制。但是:集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制。
4、集合对象的深浅拷贝
- [immutableObject copy] // 浅复制
- [immutableObject mutableCopy] //单层深复制
- [mutableObject copy] //单层深复制
- [mutableObject mutableCopy] //单层深复制
四、自定义对象
需要遵守<NSCopying>协议,并实现协议方法
CHIPerson *person = [[CHIPerson alloc] init];
CHIPerson *copyPerson = [person copy];
NSLog(@"\n person = %p\n copyPerson = %p\n", person, copyPerson);
- (id)copyWithZone:(NSZone *)zone
{
CHIPerson *person = [[self class] allocWithZone:zone];
return person;
}
打印结果:
结论:自定义对象的拷贝操作是深拷贝
本文参考链接: