在子类的子类中实现 NSCopying

Posted

技术标签:

【中文标题】在子类的子类中实现 NSCopying【英文标题】:Implementing NSCopying in Subclass of Subclass 【发布时间】:2011-05-27 06:03:38 【问题描述】:

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

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

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

【问题讨论】:

【参考方案1】:

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

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;

【讨论】:

您不应该使用allocWithZone: 而不是alloc 吗? 顺便说一句——虽然内存区域的想法很有趣,但它从未真正被证明是可行的。虽然allocWithZone: 可能是常见的签名,但alloc 这些天会很好。

以上是关于在子类的子类中实现 NSCopying的主要内容,如果未能解决你的问题,请参考以下文章

强制在子类中实现 toString()

在子类中实现纯虚方法

如何在基类中实现子类迭代器的统一接口?

在 SKNode 子类中实现 anchorPoint

确定子类是不是具有在 Python 中实现的基类方法

如何在 UIScrollView 中实现可拖动的 UIView 子类?