在C++中,深浅拷贝的区别如下:
- 浅拷贝。
缺省拷贝构造函数在拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标,也就是两个对象中成员指针变量指向同一块内存
- 深拷贝。对一个对象进行深拷贝,系统会为新对象变量中得每一个对象成员分配空间,并将原对象成员内容赋值给新对象对应的成员变量。
在iOS中,由于Objective-C自身提供了copy函数,但是深浅难辨,因此做下总结:
- 非容器变量(immutable对象与mutable对象的区分)
如下代码所示,可以得出结论,对于一个immutable对象,进行copy得到的对象是浅拷贝,进行mutableCopy得到的对象是深拷贝
NSString *string = @"animal";
NSString *stringCopy11 = [string copy];
NSMutableString *stringMutableCopy11 = [string mutableCopy];
NSString *stringCopy12 = [string mutableCopy];//非法,容易错误操作
NSMutableString *stringMutableCopy12 = [string copy];//非法,容易错误操作
NSLog(@"%p \n%p \n%p \n%p \n%p", string, stringCopy11, stringCopy12, stringMutableCopy11, stringMutableCopy12);
//output
/*
2015-09-30 21:38:50.665 HelloWorld[966:49309]
0x10a0560a8
0x10a0560a8
0x7fd2f049eb00
0x7fd2f049ce90
0x10a0560a8
*/
如下代码所示,可以得出结论,对于一个mutable对象,不管进行copy或mutableCopy得到的对象都是深拷贝
NSMutableString *mutableString1 = [[NSMutableString alloc] initWithString:@"animal"];
NSString *stringCopy21 = [mutableString1 copy];
NSMutableString *stringMutableCopy21 = [mutableString1 mutableCopy];
NSMutableString *stringCopy22 = [mutableString1 copy];//非法,容易错误操作
NSString *stringMutableCopy22 = [mutableString1 mutableCopy];//非法,容易错误操作
NSLog(@"%p \n%p \n%p \n%p \n%p", mutableString1, stringCopy21, stringCopy22, stringMutableCopy21, stringMutableCopy22);
//output
/*
2015-09-30 21:38:50.665 HelloWorld[966:49309]
0x7fd2f049d8c0
0x7fd2f049d920
0x7fd2f049e430
0x7fd2f049d940
0x7fd2f049e450
*/
- 容器变量
- 由以下实验可以看出,容器变量与非容器变量在进行copy与mutableCopy时的情况是一致的,关键在于容器变量如array中得对象都是浅拷贝,其都指向对应的同一块内存
- trueDeepCopy31、trueDeepCopy33并不是真正意义上的深拷贝,其效果还是同前面讨论的一样并不是真正意义上得深拷贝,而trueDeepCopy32才算的上时真正意义上的深拷贝,因为其对象地址、对象成员地址都都与原来的对象不同。
NSArray *a1 = @[@"dog", @"cat"];
NSArray *a2 = @[@"tiger", @"lion"];
NSArray *a3 = @[@"cow", @"sheep"];
NSArray *array = @[a1, a2, a3];
NSArray *arrayCopy11 = [array copy];
NSArray *arrayCopy12 = [array mutableCopy];
NSMutableArray *arrayMutableCopy11 = [array mutableCopy];
NSMutableArray *arrayMutableCopy12 = [array copy];
NSLog(@"%p %p %p \n%p %p %p\n%p %p %p\n%p %p %p\n%p %p %p", array, array[0], array[0][0],
arrayCopy11, arrayCopy11[0], arrayCopy11[0][0],
arrayCopy12, arrayCopy12[0], arrayCopy12[0][0],
arrayMutableCopy11, arrayMutableCopy11[0], arrayMutableCopy11[0][0],
arrayMutableCopy12, arrayMutableCopy12[0], arrayMutableCopy12[0][0]);
//output
/*
2015-09-30 22:09:07.284 HelloWorld[1284:60191]
0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52fc20 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52f010 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
*/
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];
NSArray *arrayCopy21 = [array copy];
NSArray *arrayCopy22 = [array mutableCopy];
NSMutableArray *arrayMutableCopy21 = [array mutableCopy];
NSMutableArray *arrayMutableCopy22 = [array copy];
NSLog(@"%p %p %p \n%p %p %p\n%p %p %p\n%p %p %p\n%p %p %p",
mutableArray, mutableArray[0], mutableArray[0][0],
arrayCopy21, arrayCopy21[0], arrayCopy21[0][0],
arrayCopy22, arrayCopy22[0], arrayCopy22[0][0],
arrayMutableCopy21, arrayMutableCopy21[0], arrayMutableCopy21[0][0],
arrayMutableCopy22, arrayMutableCopy22[0], arrayMutableCopy22[0][0]);
//output
/*
2015-09-30 22:09:07.284 HelloWorld[1284:60191]
0x7fa2ab52f060 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52f0b0 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52f100 0x7fa2ab52ffb0 0x10b0bc0b8
0x7fa2ab52fd80 0x7fa2ab52ffb0 0x10b0bc0b8
*/
NSArray *trueDeepCopy31 = [[NSArray alloc] initWithArray:array copyItems:YES];
NSArray *trueDeepCopy32 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]];
NSMutableArray *trueDeepCopy33 = [[NSMutableArray alloc] initWithArray:array copyItems:YES];
NSLog(@"%p %p %p \n%p %p %p\n%p %p %p", trueDeepCopy31, trueDeepCopy31[0], trueDeepCopy31[0][0],
trueDeepCopy32, trueDeepCopy32[0], trueDeepCopy32[0][0],
trueDeepCopy33, trueDeepCopy33[0], trueDeepCopy33[0][0]);
//output
/*
2015-09-30 23:13:18.877 HelloWorld[637:12672]
0x7fe7414a8d90 0x7fe7414a9f00 0x10a5050b8
0x7fe7414a96a0 0x7fe7414a9f00 0x10a5050b8
0x7fe7414a9770 0x7fe7414a9f00 0x10a5050b8
0x7fe7414aa070 0x7fe7414a9f00 0x10a5050b8
0x7fe7414a96a0 0x7fe7414a9f00 0x10a5050b8
2015-09-30 23:13:18.877 HelloWorld[637:12672]
0x7fe7414aa0c0 0x7fe7414a9f00 0x10a5050b8
0x7fe7414aaed0 0x7fe7414aab80 0x7fe7414aab20
0x7fe7414aaae0 0x7fe7414a9f00 0x10a5050b8
*/
- 自定义拷贝
自定义拷贝需要继承NSCopying、NSMutableCopying协议,重写以下两个方法。
- (id)copyWithZone:(NSZone *)zone;
- (id)mutableCopyWithZone:(NSZone *)zone;
//示例
//FSJAnimal.h
@interface FSJAnimal : NSObject
@property(nonatomic, copy) NSString *name;
@property(nonatomic, strong) NSSet *families;
-(id)initWithName:(NSString *)name;
@end
//FSJAnimal.m
@interface FSJAnimal()<NSCopying, NSMutableCopying>
@end
@implementation FSJAnimal
@synthesize name;
@synthesize families;
//懒初始化
-(NSSet*)families{
return [_internalFamilies copy];
}
-(id)initWithName:(NSString *)name
{
if(self = [super init])
{
_name = name;
_internalFamilies = [[NSMutableSet alloc] init];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
FSJAnimal *copy = [[[self class] alloc] init];
copy->name = [name copy];
copy->families = [families copy];
return copy;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
FSJAnimal *copy = [[[self class] alloc] init];
copy->name = [name mutableCopy];
copy->families = [families mutableCopy];
return copy;
}
@end