objective-c xcode memory-management hierarchy nscopying

objective c - Implementando NSCopying en Subclase de Subclase



objective-c xcode (1)

Tengo una pequeña jerarquía de clases con la que tengo problemas para implementar copyWithZone: for. He leído la documentación de NSCopying y no puedo encontrar la respuesta correcta.

Toma dos clases: Forma y Cuadrado . Cuadrado se define como:

@interface Square : Shape

No hay sorpresa allí. Cada clase tiene una propiedad, Shape tiene un "lado" int, y Square tiene un "ancho" int. Los métodos copyWithZone: se ven a continuación:

Forma

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

Cuadrado

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

Mirando la documentación, esta parece ser la manera "correcta" de hacer las cosas.

No lo es.

Si intentara establecer / acceder a la propiedad de ancho de un cuadrado devuelto por el método copyWithZone: fallaría con un error similar al siguiente:

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''

Llamando [super copyWithZone:zone]; en el método Cuadrado en realidad devuelve una Forma. Es un milagro que incluso puedas establecer la propiedad de ancho en ese método.

Dicho esto, ¿cómo se implementa NSCopying para las subclases de una manera que no las hace responsables de copiar las variables de su superclase?


Una de esas cosas que te das cuenta justo después de preguntar ...

La implementación de copyWithZone: en la superclase ( Shape ) no debería suponer que es una Shape. Así que en lugar de la manera incorrecta , como mencioné anteriormente:

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

En su lugar, debe utilizar:

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