深浅拷贝的基本定义
浅拷贝:指创建一个新对象,但新对象仍然引用原对象的内部数据。这种拷贝方式对于性能和内存管理很有优势,但需要注意一些潜在的风险。
深拷贝:指创建一个新对象,并将原对象的所有属性和子对象都复制到新对象中,形成一个完全独立的拷贝。
下面借助之前看到的两张图片来帮助理解:
深拷贝:
浅拷贝:
对于非集合元素的深浅拷贝
NSString:
NSString* a = @"hello";
NSString* b = [a copy];
NSString* c = [a mutableCopy];
NSMutableString* d = [a copy];
NSMutableString* e = [a mutableCopy];
NSLog(@"%p", a);
NSLog(@"%p", b);
NSLog(@"%p", c);
NSLog(@"%p", d);
NSLog(@"%p", e);
运行结果:
NSMutableString:
NSMutableString* a = [NSMutableString stringWithFormat:@"hello,world"];
NSString* b = [a copy];
NSString* c = [a mutableCopy];
NSMutableString* d = [a copy];
NSMutableString* e = [a mutableCopy];
NSLog(@"%p", a);
NSLog(@"%p", b);
NSLog(@"%p", c);
NSLog(@"%p", d);
NSLog(@"%p", e);
运行结果:
结论:
由上面两个测试结果可以看出,对于NSString对象来说,当进行不可变复制(copy)时,进行浅拷贝,仅复制了指针地址;进行可变复制(MutableCopy)时,进行深拷贝,既复制了指针也复制了所指内容。对于NSMutableString对象来说,无论进行哪种复制,为了保证复制对象可以进行改变,都进行了深拷贝。
对于集合元素的深浅拷贝
NSArray:
NSArray* arr = [NSArray arrayWithObjects:@"a",@"b",@"c",@"d", nil];
NSArray* arrcopy = [arr copy];
NSMutableArray* arrmucopy = [arr mutableCopy];
NSLog(@"%p", arr);
NSLog(@"%p", arrcopy);
NSLog(@"%p", arrmucopy);
NSLog(@"%p", arr[0]);
NSLog(@"%p", arrcopy[0]);
NSLog(@"%p", arrmucopy[0]);
运行结果:
arrcopy进行浅拷贝,被复制的对象和复制对象都不可以改变,仅复制了指针。
arrmucopy进行深拷贝,故而复制指针和所指内容
集合内的元素均进行浅拷贝,故而地址相同。
NSMutableArray
NSMutableArray* arr = [NSMutableArray arrayWithObjects:@"a",@"b",@"c",@"d", nil];
NSMutableArray* arrcopy = [arr copy];
NSMutableArray* arrmucopy = [arr mutableCopy];
NSLog(@"%p", arr);
NSLog(@"%p", arrcopy);
NSLog(@"%p", arrmucopy);
NSLog(@"%p", arr[0]);
NSLog(@"%p", arrcopy[0]);
NSLog(@"%p", arrmucopy[0]);
运行结果:
对可变数组进行复制,均进行深拷贝,既复制指针也复制所指的内容。
集合内的元素均进行浅拷贝,故而打印的地址相同。
注意:为什么集合内元素均为浅拷贝?(这里借助chat进行讲解,如果不对后期再回来改正)。
容器类元素的完全深拷贝
在进行完全深拷贝时,被复制对象的每一层都是对象复制。
copyItems:
copyItems: 方法是 NSArray 和 NSMutableArray 的一个方法,用于创建一个新的数组,并对数组中的元素进行拷贝。该方法会遍历原始数组的每个元素,并对每个元素执行 copy 操作,然后将拷贝后的元素添加到新的数组中。
接口部分:
@interface Person : NSObject <NSMutableCopying, NSCopying>
@property (nonatomic, strong) NSMutableString* name;
@end
实现部分:
@implementation Person
-(id) copyWithZone:(NSZone *)zone
{
Person* star = [[[self class]allocWithZone:zone]init];
star.name = [self.name mutableCopy];
return star;
}
-(id) mutableCopyWithZone:(NSZone *)zone
{
Person* star = [[[self class]allocWithZone:zone]init];
star.name = [self.name mutableCopy];
return star;
}
@end
测试程序:
NSArray* arr1= [[NSArray alloc]initWithObjects:a, nil];
NSArray* arr2 = [[NSArray alloc]initWithArray:arr1 copyItems:YES];
Person* p1 = [arr1 objectAtIndex:0];
Person* p2 = [arr2 objectAtIndex:0];
NSLog(@"%p %p", arr1, arr2);
NSLog(@"%p %p", p1, p2);
NSLog(@"%p %@", p1.name, p1.name);
NSLog(@"%p %@", p2.name, p2.name);
运行结果:
由运行结果可以看出,使用copyItems不仅对数组进行拷贝,同时对数组内的元素也进行深拷贝。
递归重写copyWithZone方法
@implementation Person
-(id) copyWithZone:(NSZone *)zone
{
Person* star = [[[self class]allocWithZone:zone]init];
star.name = [self.name mutableCopy];
return star;
}
-(id) mutableCopyWithZone:(NSZone *)zone
{
Person* star = [[[self class]allocWithZone:zone]init];
star.name = [self.name mutableCopy];
return star;
}
@end
Person* a = [[Person alloc] init];
a.name = [NSMutableString stringWithFormat:@"张三"];
Person* b = [a copy];
Person* c = [a mutableCopy];
NSLog(@"%p", a);
NSLog(@"%p", b);
NSLog(@"%p", c);
NSLog(@"%p %p %p", a.name, b.name, c.name);
运行结果:
由运行结果可以看出,这样就实现了完全拷贝。