OC数组中的深拷贝
浅拷贝与深拷贝
首先回顾下,浅拷贝:即指针拷贝,源对象和新对象指向的是同一个地址,也就是说浅拷贝要复出出来一个新的文件,但两个文件的地址还是一个。浅拷贝的话是只有不可变数组(如:NSArray,NSSet,NS字典)遇上copy,才是浅拷贝,剩下的都是深拷贝。
例如:
Dog * dog1 = [Dog new];
// 这里就是浅拷贝,即指针拷贝
Dog * dog2 = dog1;
而深拷贝,自己定义的类一般需要遵循 NSCopying, NSMutableCopying 协议,例如
Dog.h
@interface Dog : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic) NSInteger age;
@end
Dog.m
@implementation Dog
- (id)copyWithZone:(NSZone *)zone
{
Dog * dog = [[self class] allocWithZone:zone];
dog.age = self.age;
return dog;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
Dog * dog = [[self class] allocWithZone:zone];
dog.age = self.age;
return dog;
}
- (NSString *) description {
return [NSString stringWithFormat:@"dog age: %ld", self.age];
}
@end
main.m
Dog * dog1 = [Dog new];
dog1.age = 5;
NSLog(@"dog1: %p, %@", dog1, dog1);
// mutableCopy 返回的是可变对象,自然可以设置对象的属性值
Dog * dog2 = [dog1 mutableCopy];
dog2.age = 10;
// copy 返回的对象也可以设置对象的属性值
// 所以,从这里来看,其实自定义实现的 copy 和 mutableCopy 功能是一致的,都是返回可变对象的
Dog * dog2 = [dog1 copy];
dog2.age = 10;
NSLog(@"dog2: %p, %@", dog2, dog2);
可变数组的深拷贝
首先应该知道这一点:
“数组中只是存储了对象的地址,而非存储了对象的本体。”
所以,对数组进行深拷贝之后,其中对象的地址确实被重新创建啦。如下代码结果所示!
NSMutableArray * arr1 = [NSMutableArray new];
for (int i = 0; i < 3; i++) {
Dog * dog = [Dog new];
[arr1 addObject:dog];
}
NSLog(@"arr1: %p, %@", arr1, arr1);
NSMutableArray * arr2 = [arr1 mutableCopy];
NSLog(@"arr2: %p, %@", arr2, arr2);
运行结果如下:
2016-05-10 10:55:39.895 深拷贝与浅拷贝[901:303] arr1: 0x1001089c0, (
"<Dog: 0x100108430>",
"<Dog: 0x100109fc0>",
"<Dog: 0x100109fd0>"
)
2016-05-10 10:55:39.917 深拷贝与浅拷贝[901:303] arr2: 0x100301ad0, (
"<Dog: 0x100108430>",
"<Dog: 0x100109fc0>",
"<Dog: 0x100109fd0>"
)
那么,请问,数组中的 Dog 对象的空间有没有复制过去呢?
因为 “数组中只是存储了对象的地址,而非存储了对象的本体。”所以,Dog 对象的空间并没有被复制。
因此,可变数组的 “深拷贝”并没有将其中所有元素都复制,其中的对象元素只进行了浅复制!
如何解决
最简单,也是最容易理解的,即重新将所有对象都拷贝一份呗,如下代码所示:
NSMutableArray * arr2 = [NSMutableArray new];
for (int i = 0; i < arr1.count; i++) {
Dog * newDog = [arr1[i] copy];
[arr2 addObject:newDog];
}
NSLog(@"arr2: %p, %@", arr2, arr2);
总结
OC中对于数组的深拷贝,不能想当然地认为,已经将其中元素空间都拷贝了。实际上,其中的元素只是浅拷贝而已!
如果需要实现深拷贝的话,可以通过一个一个元素进行深拷贝,重新添加到可变数组中!
参考资料
- 求助深拷贝和浅拷贝的问题
http://bbs.itheima.com/thread-125376-1-1.html