5

人们经常读到,不可变类可以通过以下方式非常有效地实现 copyWithZone:

- (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;
    }
}
4

1 回答 1

3

你最好的选择是initWithMyImmutableObject在你的不可变超类中有一个初始化器。然后你的子类可以NSCopying

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

这样,属性的实际复制是在超类的方法中完成的,该方法可以访问所有需要复制的私有成员。

于 2013-10-31T19:54:13.387 回答