在子类的子类中实现 NSCopying

发布于 2024-10-08 00:22:42 字数 1229 浏览 5 评论 0原文

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

参加两门课程:形状正方形。 Square 的定义是:

@interface Square : Shape

这并不奇怪。每个类都有一个属性,Shape 有一个“sides” int,Square 有一个“width” int。 copyWithZone: 方法如下所示:

Shape

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

Square

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

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

事实并非如此。

如果您尝试设置/访问 copyWithZone: 方法返回的 Square 的宽度属性,将会失败出现类似于以下错误:

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。你甚至可以在该方法中设置宽度属性,这真是一个奇迹。

话虽如此,如何为子类实现 NSCopying,而不会让子类负责复制其超类的变量?

I have a small class hierarchy that I'm having trouble implementing copyWithZone: for. I've read the NSCopying documentation, and I can't find the correct answer.

Take two classes: Shape and Square. Square is defined as:

@interface Square : Shape

No surprise there. Each class has one property, Shape has a "sides" int, and Square has a "width" int. The copyWithZone: methods are seen below:

Shape

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

Square

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

Looking at the documentation, this seems to be the "right" way to do things.

It is not.

If you were to try to set/access the width property of a Square returned by the copyWithZone: method, it would fail with an error similar to the one below:

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'

Calling [super copyWithZone:zone]; in the Square method actually returns a Shape. It's a miracle you're even allowed to set the width property in that method.

That having been said, how does one implement NSCopying for subclasses in a way that does not make them responsible for copying the variables of its superclass?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

待天淡蓝洁白时 2024-10-15 00:22:42

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

超类 (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;
}

One of those things you realize right after asking...

The implementation of copyWithZone: in the superclass (Shape) shouldn't be assuming it's a Shape. So instead of the wrong way, as I mentioned above:

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

You should instead use:

- (id)copyWithZone:(NSZone *)zone {
    Shape *s = [[[self class] allocWithZone:zone] init]; // <-- NOTE CHANGE
    s.sides = self.sides;
    return s;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文