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中对于数组的深拷贝,不能想当然地认为,已经将其中元素空间都拷贝了。实际上,其中的元素只是浅拷贝而已!

如果需要实现深拷贝的话,可以通过一个一个元素进行深拷贝,重新添加到可变数组中!

参考资料

  1. 求助深拷贝和浅拷贝的问题
    http://bbs.itheima.com/thread-125376-1-1.html
posted @ 2016-05-11 09:30  lvye1221  阅读(11)  评论(0编辑  收藏  举报