23

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

参加两个课程:ShapeSquare。正方形定义为:

@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'

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

话虽如此,如何以一种不让子类负责复制其超类的变量的方式为子类实现 NSCopying?

4

1 回答 1

49

询问后您立即意识到的其中一件事...

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;
}
于 2010-12-17T17:07:25.000 回答