Is returning [self retain] in copyWithZone for immutable classes with mutable subclasses really safe / a good idea?

给你一囗甜甜゛ 提交于 2019-12-07 06:46:03

问题


One often reads, that immutable classes can implement copyWithZone very efficiently in the following way:

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

The idea behind that implementation is obvious: The original and the copy are both immutable instances and they will always have exactly the same content, so why not let both point to the same storage by retaining the original and avoid the overhead of copying.

However, what will happen if there is a mutable subclass? With a clean architecture, where a subclass does not have to care about implementation details of its base class, the mutable subclass should be fine to implement copyWithZone in this way:

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

But what does this mean with the above superclass implementation of copyWithZone? The subclass is mutable, so although the copy still is immutable, the original now is mutable, but the subclass copyWithZone thanks to the superclass implementation operates on a retained instance of itself: self and myCopy both point the the same instance, so if I later change the value of mutableOriginal.myMember, then that will also change immutableCopy.myMember, which is just plain wrong.

So shouldn't immutable classes better implement copyWithZone in the following way?

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

回答1:


Your best option would be to have an initWithMyImmutableObject initialiser in your immutable superclass. Your subclass can then just implement NSCopying with

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

That way the actual copying of properties is done in a method of your superclass, which has access to all private members that need to be copied.



来源:https://stackoverflow.com/questions/19714985/is-returning-self-retain-in-copywithzone-for-immutable-classes-with-mutable-su

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!