iphone objective-c cocoa-touch copywithzone

iphone - Las mejores prácticas al implementar copyWithZone:



objective-c cocoa-touch (4)

  1. Siempre debe usar [[self class] allocWithZone:zone] para asegurarse de que está creando una copia utilizando la clase adecuada. El ejemplo que das para 002 muestra exactamente por qué: las subclases llamarán a [super copyWithZone:zone] y esperan obtener una instancia de la clase apropiada, no una instancia de la superclase.

  2. Accedo a los ivars directamente, por lo que no tengo que preocuparme por los efectos secundarios que pueda agregar al programador de propiedades (por ejemplo, generar notificaciones) más adelante. Tenga en cuenta que las subclases son libres de anular cualquier método. En su ejemplo, está enviando dos mensajes adicionales por ivar. Lo implementaría de la siguiente manera:

Código:

- (id)copyWithZone:(NSZone *)zone { Crime *newCrime = [super copyWithZone:zone]; newCrime->_month = [_month copyWithZone:zone]; newCrime->_category = [_category copyWithZone:zone]; // etc... return newCrime; }

Por supuesto, ya sea que copie los ivars, los retenga o simplemente los asigne, debe reflejar lo que hacen los setters.

Estoy tratando de aclarar algunas cosas en mi cabeza sobre la implementación de copyWithZone: ¿alguien puede comentar sobre lo siguiente ...

// 001: Crime is a subclass of NSObject. - (id)copyWithZone:(NSZone *)zone { Crime *newCrime = [[[self class] allocWithZone:zone] init]; if(newCrime) { [newCrime setMonth:[self month]]; [newCrime setCategory:[self category]]; [newCrime setCoordinate:[self coordinate]]; [newCrime setLocationName:[self locationName]]; [newCrime setTitle:[self title]]; [newCrime setSubtitle:[self subtitle]]; } return newCrime; } // 002: Crime is not a subclass of NSObject. - (id)copyWithZone:(NSZone *)zone { Crime *newCrime = [super copyWithZone:zone]; [newCrime setMonth:[self month]]; [newCrime setCategory:[self category]]; [newCrime setCoordinate:[self coordinate]]; [newCrime setLocationName:[self locationName]]; [newCrime setTitle:[self title]]; [newCrime setSubtitle:[self subtitle]]; return newCrime; }

En 001:

  1. ¿Es mejor escribir el nombre de clase directamente [[Crime allocWithZone:zone] init] o debería usar [[[self Class] allocWithZone:zone] init] ?

  2. ¿Está bien usar [self month] para copiar iVars o debería acceder directamente a _month es decir, _month ?


¿Qué tal este que implementa una copia profunda?

/// Class Foo has two properties: month and category - (id)copyWithZone:(NSZone *zone) { Foo *newFoo; if ([self.superclass instancesRespondToSelector:@selector(copyWithZone:)]) { newFoo = [super copyWithZone:zone]; } else { newFoo = [[self.class allocWithZone:zone] init]; } newFoo->_month = [_month copyWithZone:zone]; newFoo->_category = [_category copyWithZone:zone]; return newFoo; }


El comportamiento de copiado predeterminado del método copyWithZone: con objetos proporcionados por SDK es "copia superficial". Eso significa que si llama a copyWithZone: en el objeto NSString , creará una copia superficial pero no una copia en profundidad. La diferencia entre la copia superficial y la profunda son:

Una copia superficial de un objeto solo copiará las referencias a los objetos de la matriz original y los colocará en la nueva matriz.

Una copia profunda realmente copiará los objetos individuales contenidos en el objeto. Esto se hace enviando a cada objeto individual el mensaje copyWithZone: en su método de clase personalizado.

INSHORT: Para obtener una copia poco profunda, llame a " retain o " strong en todas las variables de instancia. Para obtener una copia profunda llame a copyWithZone: en todas las variables de instancia en su clase personalizada copyWithZone: implementation. Ahora es tu elección elegir.


Este es mi modelo.

#import <Foundation/Foundation.h> @interface RSRFDAModel : NSObject @property (nonatomic, assign) NSInteger objectId; @property (nonatomic, copy) NSString *name; @property (nonatomic, strong) NSArray<RSRFDAModel *> *beans; @end #import "RSRFDAModel.h" @interface RSRFDAModel () <NSCopying> @end @implementation RSRFDAModel -(id)copyWithZone:(NSZone *)zone { RSRFDAModel *model = [[[self class] allocWithZone:zone] init]; model.objectId = self.objectId; model.name = self.name; model.beans = [self.beans mutableCopy]; return model; } @end