2013-10-31 10 views
5

一个经常读,是一成不变的类可以通过以下的方式非常有效地实现copyWithZone:在copyWithZone中为[不可变类]返回[self retain]带有可变子类真的很安全/一个好主意?

- (id) copyWithZone:(NSZone*)zone 
{ 
    return [self retain]; 
} 

,落实背后的想法是显而易见的: 的原件和复印件都是不可变的情况下,他们将永远有完全相同相同的内容,所以为什么不让两者通过保留原来的指向相同的存储并避免复制的开销。

但是,如果存在可变子类会发生什么? 用干净的架构,其中一个子类不必在意它的基类的实现细节,易变的子类应罚款来实现这样copyWithZone:

- (id) copyWithZone:(NSZone*)zone 
{ 
    MyClass* myCopy = [super copyWithZone:zone]; 
    myCopy->myMember = [myMember copyWithZone:zone]; 
    return myCopy; 
} 

但是这是什么意思上述copyWithZone的超类实现? 子类是可变的,所以尽管拷贝仍然是不可变的,但是原来的变量是可变的,但是由于超类的实现,子类copyWithZone对它自己的保留实例进行操作:self和myCopy都指向相同的实例,所以如果我稍后更改mutableOriginal.myMember的值,那么这也会更改immutableCopy.myMember,这显然是错误的。

因此,不应该不可变的类更好地实现copyWithZone在以下方式?

- (id) copyWithZone:(NSZone*)zone 
{ 
    if([[self class] isMemberOfClass:[MyBaseClass class]]) 
     return [self retain]; 
    else 
    { 
     MyBaseClass* myCopy = [[self alloc] init]; 
     myCopy->myBaseMember = [myBaseMember copyWithZone:zone]; 
     return myCopy; 
    } 
} 
+2

不完全。我不认为应该按照上面列出的任何一种方法来执行“复制”。复制*非常*固有。你最好不要调用'[super copy]',但如果需要的话分配一个干净的新实例。 – 2013-10-31 19:47:00

回答

3

你最好的选择是在你不可改变的超initWithMyImmutableObject初始化器。然后,您的子类可以只实现NSCopying

- (id) copyWithZone:(NSZone*)zone { 
    return [[[self superclass] alloc] initWithMyImmutableObject:self] 
} 

这样性质的实际复制在你的超类,它可以访问需要被复制的所有私有成员的方法来完成。