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

分为两类: Shape 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属性,这是一个奇迹。

话虽这么说,如何以一种不使子类负责复制其父类(super class)变量的方式实现子类的NSCopying?

最佳答案

问完后您立即意识到的事情之一...

父类(super class)( Shape )中copyWithZone:的实现不应假定它是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;
}

10-08 05:26