在子类的子类中实现NSCopying

时间:2010-12-17 17:01:57

标签: objective-c xcode memory-management hierarchy nscopying

我有一个小的类层次结构,我无法实现copyWithZone:。我已经阅读了NSCopying文档,但我找不到正确答案。

选择两个课程: Shape Square 。 Square定义为:

@interface Square : Shape

那里不足为奇。每个类都有一个属性,Shape有一个“sides”int,而Square有一个“width”int。 copyWithZone:方法如下所示:

形状

- (id)copyWithZone:(NSZone *)zone {
    Shape *s = [[Shape alloc] init];
    s.sides = self.sides;
    return s;
}

方形

- (id)copyWithZone:(NSZone *)zone {
    Square *s = (Square *)[super copyWithZone:zone];
    s.width = self.width;
    return s;
}

查看文档,这似乎是“正确”的做事方式。

不是。

如果您尝试设置/访问copyWithZone:方法返回的Square的width属性,将失败,其错误类似于下面的错误:

2010-12-17 11:55:35.441 Hierarchy[22617:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Shape setWidth:]: unrecognized selector sent to instance 0x10010c970'

在Square方法中调用[super copyWithZone:zone];实际上会返回一个Shape。你甚至可以在该方法中设置width属性,这是一个奇迹。

有人说过,如何以不使其负责复制其超类的变量的方式为子类实现NSCopying

1 个答案:

答案 0 :(得分:48)

在询问后你意识到的其中一件事......

超类中的copyWithZone: Shape )的实现不应该假设它是一个Shape。因此,正如我上面提到的那样,而不是错误的方式:

- (id)copyWithZone:(NSZone *)zone {
    Shape *s = [[Shape allocWithZone:zone] init];
    s.sides = self.sides;
    return s;
}

您应该使用:

- (id)copyWithZone:(NSZone *)zone {
    Shape *s = [[[self class] allocWithZone:zone] init]; // <-- NOTE CHANGE
    s.sides = self.sides;
    return s;
}