65 votes

Copier & mutableCopy?

Quelle est la différence entre la "copie" et "mutableCopy"?

EDIT_001:

Mon premier post était un peu le bazar, en partie en raison d'un manque de compréhension et en partie en raison d'un bit d'erreur du pilote de ma part. Voici ma tentative de mieux expliquer comment "copier" et "mutableCopy" de travail.

// ** NSArray **
NSArray *myArray_imu = [NSArray  arrayWithObjects:@"abc", @"def", nil];

// No copy, increments retain count, result is immutable
NSArray *myArray_imuCopy = [myArray_imu copy];

// Copys object, result is mutable 
NSArray *myArray_imuMuta = [myArray_imu mutableCopy];

[myArray_imuCopy release];
[myArray_imuMuta release];

.

// ** NSMutableArray **
NSMutableArray *myArray_mut = [NSMutableArray arrayWithObjects:@"A", @"B", nil];

// Copys object, result is immutable
NSMutableArray *myArray_mutCopy = [myArray_mut copy];

// Copys object, result is mutable
NSMutableArray *myArray_mutMuta = [myArray_mut mutableCopy];

[myArray_mutCopy release];
[myArray_mutMuta release];

EDIT_002:

  1. mutableCopy retourne toujours une mutable résultat.
  2. copie retourne toujours immuable résultat.

merci pour toutes les réponses, les commentaires ... très apprécié.

gary

72voto

Asher Dunn Points 1702

copy et mutableCopy sont définies dans les différents protocoles (NSCopying et NSMutableCopying, respectivement), et NSArray est conforme à la fois. mutableCopy est défini pour NSArray (et pas seulement NSMutableArray) et vous permet de faire des mutable copie d'une origine immuable tableau:

// create an immutable array
NSArray *arr = [NSArray arrayWithObjects: @"one", @"two", @"three", nil ];

// create a mutable copy, and mutate it
NSMutableArray *mut = [arr mutableCopy];
[mut removeObject: @"one"];

Résumé:

  • vous pouvez compter sur le résultat de l' mutableCopy à être mutables, quel que soit le type d'origine. Dans le cas des tableaux, le résultat devrait être un NSMutableArray.
  • vous ne peut pas dépendre du résultat de l' copy à mutable! copying un NSMutableArray peut retourner un NSMutableArray, puisque c'est le nom de la classe d'origine, mais copying arbitraire NSArray instance ne serait pas.

Edit: re-lire l'original de votre code à la lumière de la Marque Bessey la réponse. Lorsque vous créez une copie de votre tableau, bien sûr, vous pouvez toujours modifier l'original, indépendamment de ce que vous faites avec la copie. copy vs mutableCopy détermine si le nouveau tableau est mutable.

Edit 2: Fixe mon (faux) hypothèse qu' NSMutableArray -copy serait de retour d'un NSMutableArray.

8voto

Mark Bessey Points 13931

Je crois que vous avez mal interprété comment copier et mutableCopy travail. Dans ton premier exemple, myArray_COPY est immuable copie de myArray. Ayant fait la copie, vous pouvez manipuler le contenu de l'original myArray, et affecte pas le contenu de myArray_COPY.

Dans le deuxième exemple, vous créez une mutable copie de myArray, ce qui signifie que vous pouvez modifier une copie de la matrice, sans affecter les autres.

Si je change le premier exemple d'essayer d'insérer/supprimer des objets de myArray_COPY, il échoue, juste comme vous le souhaitez.


Peut-être penser à une utilisation typique de cas d'aide. C'est souvent le cas de ce que vous pourriez écrire une méthode qui prend un NSArray * paramètre, et, essentiellement, les stocke pour une utilisation ultérieure. Vous pouvez faire cela de cette façon:

- (void) doStuffLaterWith: (NSArray *) objects {
  myObjects=[objects retain];
}

...mais vous avez le problème que la méthode peut être appelée avec un NSMutableArray comme argument. Le code qui a créé le groupe peut manipuler entre le moment où le doStuffLaterWith: la méthode est appelée, et lorsque, plus tard, vous devez utiliser la valeur. Dans un environnement multi-thread application, le contenu de la matrice pourrait même être changé pendant que vous êtes en itérant sur elle, ce qui peut causer certains intéressant de bugs.

Si vous au lieu de faire ceci:

- (void) doStuffLaterWith: (NSArray *) objects {
  myObjects=[objects copy];
}

..alors la copie crée un instantané du contenu de la matrice au moment de l'appel de la méthode.

5voto

Corey Floyd Points 16747

La "copie" méthode retourne un objet créé par la mise en œuvre de NSCopying protocoles copyWithZone:

Si vous envoyez NSString une copie de message:

NSString* myString;

NSString* newString = [myString copy];

La valeur de retour sera un NSString (non modifiable)


Le mutableCopy méthode retourne un objet créé par la mise en œuvre de NSMutableCopying du protocole de mutableCopyWithZone:

En envoyant:

NSString* myString;

NSMutableString* newString = [myString mutableCopy];

La valeur de retour VA être mutables.


Dans tous les cas, l'objet doit mettre en œuvre le protocole, signifiant qu'il va créer la nouvelle copie de l'objet et de vous le renvoyer.


Dans le cas de NSArray il y a un niveau supplémentaire de complexité en ce qui concerne profonde et peu profonde de la copie.

D'une copie d'un NSArray ne copie que les références aux objets du tableau d'origine et le placer dans le nouveau tableau.

Le résultat étant que:

NSArray* myArray;

NSMutableArray* anotherArray = [myArray mutableCopy];

[[anotherArray objectAtIndex:0] doSomething];

Affecte également l'objet à l'indice 0 dans le tableau d'origine.


Une copie sera réellement copier les différents objets contenus dans le tableau. De ce fait par l'envoi de chaque objet, le "copyWithZone:" message.

NSArray* myArray;

NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:myArray
                                                       copyItems:YES];

Édité pour enlever mon hypothèse erronée sur mutable objet de copie

5voto

robertt almeida Points 21
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray
                                                           copyItems:YES];

permettra de créer anotherArray qui est une copie de l' oldArray à 2 niveaux de profondeur. Si un objet d' oldArray est un Tableau. Ce qui est généralement le cas dans la plupart des applications.

Eh bien, si nous avons besoin d'une Vraie Copie en Profondeur que nous pouvons utiliser,

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
    [NSKeyedArchiver archivedDataWithRootObject: oldArray]];

Cela permettrait de s'assurer que tous les niveaux sont réellement copiés en conservant la mutabilité de l'objet original à chaque niveau.

Robert Clarence D'Almeida, Bangalore, En Inde.

3voto

Vous appelez addObject et removeObjectAtIndex sur le tableau d'origine, plutôt que sur la nouvelle copie que vous avez créée. L'appel de copy vs mutableCopy n'affecte que la mutabilité de la nouvelle copie de l'objet, et non de l'objet d'origine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X