一劳永逸:深层复制对象

时间:2015-08-21 21:28:53

标签: objective-c

我已经看到很多尝试在Stackoverflooooooow上回答这个问题,没有人对我感到满意。

我有一个Person类,只有一个公共name属性,其子类为NSObject。在main我跑:

Person *alex = [[Person alloc] init];
alex.name = @"alex"
NSLog(@"name: %@ %p", alex.name, alex.name");

将打印到控制台

2015-08-21 21:53:34.047 Test[29456:5960428] name: alex 0x108dfd640

我发现用于复制的两个方法都实现了copyWithZone:协议的<NSCopying>选择器,我把它放在Person类中。

1)此选择器的第一个版本是:

- (id) copyWithZone:(NSZone *) zone
{
    Person *personCopy = [[[self class] allocWithZone:zone] init];
    personCopy.name = [self.name copyWithZone:zone];
    // i've also tried: personCopy.name = [self.name copy];
    return personCopy;
}

在主要的i中运行

Person *aCopyOfAlex = [alex copy]
NSLog(@"name: %@ %p", aCopyOfAlex.name, aCopyOfAlex.name");

记录

2015-08-21 21:53:34.047 Test[29456:5960428] name: alex 0x108dfd640

Person副本实例 不同,但副本和原始名称属性指向相同的位置。

2)这个选择器的第二个版本使用了一个归档器(我想这需要一些时间 - 特别是如果我有很多属性要深入复制?)然后是unarchiver:

- (id) copyWithZone:(NSZone *) zone
{
    Person *personCopy = [[[self class] allocWithZone:zone] init];
    NSData *buffer = [NSKeyedArchiver archivedDataWithRootObject:self.name];
    personCopy.name = [NSKeyedUnarchiver unarchiveObjectWithData:buffer];
    return personCopy;
}

在主要我再次运行

Person *aCopyOfAlex = [alex copy]
NSLog(@"name: %@ %p", aCopyOfAlex.name, aCopyOfAlex.name");

记录

2015-08-21 21:53:34.047 Test[29456:5960428] name: alex 0x7fa80969e4a0

这次Person副本实例名称属性都指向不同的位置。

终于到了一个问题!有人可以说哪种方法是正确的(如果有的话),好吗?似乎第二个做了我想要的,并且将是一个真正的深层复制..

谢谢!

2 个答案:

答案 0 :(得分:2)

你的第一段代码没有错。你看到的是用字符串完成的优化。由于您从一个不可变的字符串文字开始,复制它只会让您返回相同的对象。这不是问题,因为它是不可变的。

您对Person copyWithZone:的第二次实施是过度的。不要为存档而烦恼。

答案 1 :(得分:0)

虽然我不得不同意@rmaddy关于第二个对于这个确切案例而言过度杀戮的事情,但它是唯一一个(从你发布的两个)中执行深层复制的案例。

请参阅What is the difference between a deep copy and a shallow copy?,了解深度复制的详细说明。

如果你有一个可变属性说NSMutableArray *addresses,第一种方法会让你有两个Person实例共享相同的NSMutableArray个实例,这意味着如果你改变地址,你会看到两个Person实例中的更改,因为它们确实共享相同的数组。

请注意,第二个将取决于Person中的属性是否确实可以存档。