在子类的子类中实现NSCopying

Cra*_*tis 22 xcode memory-management objective-c hierarchy nscopying

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

选择两个类:ShapeSquare.Square定义为:

@interface Square : Shape
Run Code Online (Sandbox Code Playgroud)

这并不奇怪.每个类都有一个属性,Shape有一个"sides"int,而Square有一个"width"int.该copyWithZone:方法被认为如下:

形状

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

广场

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

看一下文档,这似乎是做事的"正确"方式.

它不是.

如果您尝试设置/访问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'
Run Code Online (Sandbox Code Playgroud)

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

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

Cra*_*tis 48

在询问之后你意识到的其中一件事......

copyWithZone:超类(Shape)中的实现不应该假设它是一个Shape.因此,正如我上面提到的那样,而不是错误的方式:

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

您应该使用:

- (id)copyWithZone:(NSZone *)zone {
    Shape *s = [[[self class] allocWithZone:zone] init]; // <-- NOTE CHANGE
    s.sides = self.sides;
    return s;
}
Run Code Online (Sandbox Code Playgroud)

  • 暂时不谈 - 虽然记忆区的概念很有意思,但它从未真正证明是可行的.虽然`allocWithZone:`可能是常见的签名,但`alloc`这些天你会很好. (4认同)
  • 你不应该使用`allocWithZone:`而不是`alloc`? (2认同)