我有一个很小的类层次结构,在实现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;
}