web-dev-qa-db-fra.com

Comment copier un objet dans l'objectif c

J'ai besoin de copier en profondeur un objet personnalisé qui a ses propres objets. J'ai lu et suis un peu confus quant à la façon d'hériter NSCopying et d'utiliser NSCopyObject Est-ce que quelqu'un peut me donner un coup de main? Merci d'avoir lu!

108
ben

Comme toujours avec les types de référence, il existe deux notions de "copie". Je suis sûr que vous les connaissez, mais pour être complet.

  1. Une copie au niveau du bit. En cela, nous copions simplement le bit de mémoire pour un bit - c'est ce que fait NSCopyObject. Presque toujours, ce n'est pas ce que vous voulez. Les objets ont un état interne, d'autres objets, etc., et supposent souvent qu'ils sont les seuls à contenir des références à ces données. Les copies au niveau du bit cassent cette hypothèse.
  2. Une copie profonde et logique. En cela, nous faisons une copie de l'objet, mais sans le faire réellement - nous voulons un objet qui se comporte de la même manière, mais qui n'est pas (nécessairement) un clone identique à celui de la mémoire - le manuel Objective C appelle un tel objet "fonctionnellement indépendant" de son original. Parce que les mécanismes pour réaliser ces copies "intelligentes" varient d'une classe à l'autre, nous demandons aux objets eux-mêmes de les exécuter. C'est le protocole NSCopying.

Vous voulez le dernier. S'il s'agit de l'un de vos propres objets, vous devez simplement adopter le protocole NSCopying et mettre en œuvre - (id) copyWithZone: (NSZone *). Vous êtes libre de faire ce que vous voulez. bien que l'idée soit que vous fassiez une copie de vous-même et que vous le rendiez. Vous appelez copyWithZone sur tous vos champs pour en faire une copie complète. Un exemple simple est

@interface YourClass : NSObject <NSCopying> 
{
   SomeOtherObject *obj;
}

// In the implementation
-(id)copyWithZone:(NSZone *)zone
{
  // We'll ignore the zone for now
  YourClass *another = [[YourClass alloc] init];
  another.obj = [obj copyWithZone: zone];

  return another;
}
187
Adam Wright

La documentation Apple dit

Une version de sous-classe de la méthode copyWithZone: doit envoyer le message super d'abord, pour incorporer sa mise en oeuvre, à moins que la sous-classe descend directement de NSObject.

ajouter à la réponse existante 

@interface YourClass : NSObject <NSCopying> 
{
   SomeOtherObject *obj;
}

// In the implementation
-(id)copyWithZone:(NSZone *)zone
{
  YourClass *another = [super copyWithZone:zone];
  another.obj = [obj copyWithZone: zone];

  return another;
}
23
Saqib Saud

Je ne connais pas la différence entre ce code et le mien, mais cette solution me pose problème. J'ai donc lu un peu plus et j'ai constaté qu'il fallait définir l'objet avant de le renvoyer. Je veux dire quelque chose comme:

#import <Foundation/Foundation.h>

@interface YourObject : NSObject <NSCopying>

@property (strong, nonatomic) NSString *nombre;//nombre del medicamento
@property (strong, nonatomic) NSString *linea;//linea a la que pertenece
@property (strong, nonatomic) NSMutableString *tags;//palabras por las que se puede encontrar en el buscador
@property (strong, nonatomic) NSString *htmlSource;//código html para mostrar su contenido
@property (strong, nonatomic) NSMutableString *obj;

-(id) copyWithZone: (NSZone *) zone;

@end


@implementation YourObject


-(id) copyWithZone: (NSZone *) zone
{
    YourObject *copy = [[YourObject allocWithZone: zone] init];

    [copy setNombre: self.nombre];
    [copy setLinea: self.linea];
    [copy setTags: self.tags];
    [copy setHtmlSource: self.htmlSource];

    return copy;
}

J'ai ajouté cette réponse parce que j'ai beaucoup de problèmes avec ce problème et que je ne sais pas pourquoi cela se produit. Je ne connais pas la différence, mais ça marche pour moi et peut-être que ça peut être utile pour les autres aussi:)

21
Felipe Quirós
another.obj = [obj copyWithZone: zone];

Je pense que cette ligne provoque une fuite de mémoire, car vous accédez à obj par une propriété qui est (je suppose) déclarée comme retain. Donc, conservez le nombre sera augmenté par la propriété et copyWithZone.

Je crois que ça devrait être:

another.obj = [[obj copyWithZone: zone] autorelease];

ou:

SomeOtherObject *temp = [obj copyWithZone: zone];
another.obj = temp;
[temp release]; 
2
Szuwar_Jr

Il y a aussi l'utilisation de l'opérateur -> pour la copie. Par exemple:

-(id)copyWithZone:(NSZone*)zone
{
    MYClass* copy = [MYClass new];
    copy->_property1 = self->_property1;
    ...
    copy->_propertyN = self->_propertyN;
    return copy;
}

Le raisonnement est que l'objet copié résultant doit refléter l'état de l'objet d'origine. Le "." L’opérateur peut introduire des effets secondaires car celui-ci appelle des accesseurs qui peuvent à leur tour contenir une logique.

0
Alex Nolasco