Meilleure pratique lors de l’implémentation de copyWithZone:

J’essaie de clarifier quelques choses dans ma tête concernant l’implémentation de copyWithZone:

 // 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. Est-il préférable d’écrire directement le nom de la classe [[Crime allocWithZone:zone] init] ou devrais-je utiliser [[[self Class] allocWithZone:zone] init] ?

  2. Est-il correct d’utiliser [self month] pour copier les iVars ou dois-je accéder directement à _month exemple _month ?

  1. Vous devez toujours utiliser [[self class] allocWithZone:zone] pour vous assurer que vous créez une copie en utilisant la classe appropriée. L’exemple que vous donnez pour 002 montre exactement pourquoi: les sous-classes appellent [super copyWithZone:zone] et s’attendent à récupérer une instance de la classe appropriée, et non une instance de la super classe.

  2. J’accède directement aux ivars, donc je n’ai pas besoin de m’inquiéter des effets secondaires que je pourrais append au setter de propriétés (par exemple, générer des notifications) plus tard. Gardez à l’esprit que les sous-classes sont libres de remplacer n’importe quelle méthode. Dans votre exemple, vous envoyez deux messages supplémentaires par ivar. Je l’implémenterais comme suit:

Code:

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

Bien sûr, que vous copiiez les ivars, que vous les conserviez ou que vous les affectiez simplement, vous devriez savoir ce que font les créateurs.

Le comportement de copie par défaut de copyWithZone: méthode avec les objects fournis par SDK est “copie superficielle”. Cela signifie que si vous appelez copyWithZone: sur l’object NSSsortingng , cela créera une copie superficielle mais pas une copie profonde. La différence entre copie superficielle et profonde est la suivante:

Une copie superficielle d’un object ne copiera que les références aux objects du tableau d’origine et les placera dans le nouveau tableau.

Une copie profonde copiera réellement les objects individuels contenus dans l’object. Cela se fait en envoyant à chaque object individuel le message copyWithZone: dans votre méthode de classe personnalisée.

INSHORT: Pour obtenir une copie superficielle, vous appelez l’option Reste ou strong sur toutes les variables d’instance. Pour obtenir une copie copyWithZone: appelez copyWithZone: sur toutes les variables d’instance de votre classe personnalisée copyWithZone: implémentation. Maintenant, c’est à vous de choisir.

Ceci est mon modèle

 #import  @interface RSRFDAModel : NSObject @property (nonatomic, assign) NSInteger objectId; @property (nonatomic, copy) NSSsortingng *name; @property (nonatomic, strong) NSArray *beans; @end #import "RSRFDAModel.h" @interface RSRFDAModel ()  @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 

Que diriez-vous de celui qui implémente Deep Copy:

 /// 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; }