web-dev-qa-db-fra.com

Comment copy et mutableCopy s'appliquent-ils à NSArray et NSMutableArray?

Quelle est la différence entre copy et mutableCopy lorsqu’il est utilisé avec un NSArray ou un NSMutableArray?

Ceci est ma compréhension. est-ce correct?

// ** 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];

// Both must be released later

// ** 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];

// Both must be released later
64
fuzzygoat

copy et mutableCopy sont définis dans différents protocoles (NSCopying et NSMutableCopying, respectivement), et NSArray est conforme aux deux. mutableCopy est défini pour NSArray (pas seulement NSMutableArray) et vous permet de créer une copie mutable d'un tableau initialement immuable:

// 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 mutableCopy pour être mutable, quel que soit le type d'origine. Dans le cas de tableaux, le résultat devrait être un NSMutableArray.
  • vous ne pouvez pas compter sur le résultat de copy pour être mutable! copying un NSMutableArraymay renvoyer un NSMutableArray, puisqu'il s'agit de la classe d'origine, mais copying de toute instance NSArray arbitraire ne le ferait pas.

Edit: relisez votre code original à la lumière de la réponse de Mark Bessey. Lorsque vous créez une copie de votre tableau, vous pouvez bien entendu modifier l’original, quel que soit le résultat de la copie. copy vs mutableCopy détermine si le tableau new est modifiable.

Edit 2: Corrige mon (fausse) hypothèse selon laquelle NSMutableArray -copy renverrait une NSMutableArray.

71
Asher Dunn

Je pense que vous devez avoir mal interprété le fonctionnement de copy et mutableCopy. Dans votre premier exemple, myArray_COPY est une copie immuable de myArray. Une fois la copie réalisée, vous pouvez manipuler le contenu du myArray d'origine sans affecter le contenu de myArray_COPY. 

Dans le deuxième exemple, vous créez une copie mutable de myArray, ce qui signifie que vous pouvez modifier l’une ou l’autre des copies du tableau sans affecter l’autre.

Si je modifie le premier exemple pour essayer d'insérer/de supprimer des objets de myArray_COPY, cela échoue, comme vous le souhaitiez.


Peut-être que penser à un cas d'utilisation typique pourrait aider. Il arrive souvent que vous écriviez une méthode qui prend un paramètre NSArray * et la stocke essentiellement pour une utilisation ultérieure. Vous pouvez le faire de cette façon:

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

... mais le problème est que la méthode peut être appelée avec un argument NSMutableArray. Le code qui a créé le tableau peut le manipuler entre le moment où la méthode doStuffLaterWith: est appelée et le moment où vous devez utiliser la valeur par la suite. Dans une application multithread, le contenu du tableau pourrait même être modifié pendant que vous parcourez le tableau , ce qui peut entraîner des bogues intéressants.

Si vous faites plutôt ceci:

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

..then the copy crée un instantané du contenu du tableau au moment de l'appel de la méthode.

8
Mark Bessey

La méthode "copy" renvoie l'objet créé en implémentant les protocoles NSCopying copyWithZone:

Si vous envoyez un message de copie à NSString:

NSString* myString;

NSString* newString = [myString copy];

La valeur de retour sera une NSString (non mutable)


La méthode mutableCopy renvoie l'objet créé en implémentant mutableCopyWithZone du protocole NSMutableCopying:

En envoyant:

NSString* myString;

NSMutableString* newString = [myString mutableCopy];

La valeur de retourSERAmutable.


Dans tous les cas, l'objet doit implémenter le protocole, ce qui signifie qu'il créera le nouvel objet de copie et vous le retournera.


Dans le cas de NSArray, la copie superficielle et profonde présente un niveau de complexité supplémentaire.

Une copie superficielle d'un tableau NSArray ne copie que les références aux objets du tableau d'origine et les place dans le nouveau tableau.

Le résultat étant que:

NSArray* myArray;

NSMutableArray* anotherArray = [myArray mutableCopy];

[[anotherArray objectAtIndex:0] doSomething];

Cela affectera également l’objet à l’index 0 du tableau d’origine.


Une copie en profondeur copiera en réalité les objets individuels contenus dans le tableau. Ceci est fait en envoyant à chaque objet individuel le message "copyWithZone:".

NSArray* myArray;

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

Modifié pour supprimer mon hypothèse erronée sur la copie d'objet modifiable

5
Corey Floyd
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray
                                                           copyItems:YES];

créera anotherArray qui est une copie de oldArray sur 2 niveaux. Si un objet de oldArray est un tableau. Ce qui est généralement le cas dans la plupart des applications.

Eh bien, si nous avons besoin d’un True Deep Copy nous pourrions utiliser,

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

Cela garantirait que tous les niveaux sont réellement copiés en conservant la mutabilité de l'objet d'origine à chaque niveau.

Robert Clarence D'Almeida, .__ Bangalore, Inde.

5
robertt almeida

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.

3

Pour le dire simplement, 

  • copy renvoie une copie immuable (non modifiable) du tableau, 
  • mutableCopy renvoie une copie mutable (pouvant être modifiée) du tableau. 

Copier (dans les deux cas) signifie que vous obtenez un nouveau tableau "rempli" avec des références d'objet au tableau d'origine (c'est-à-dire que les mêmes objets (originaux) sont référencés dans les copies. 

Si vous ajoutez de nouveaux objets à mutableCopy, ils sont uniques à mutableCopy. Si vous supprimez des objets de mutableCopy, ils sont supprimés du tableau d'origine. 

Pensez à la copie dans les deux cas, comme un instantané dans le tableau d'origine au moment de la création de la copie.

2
Wizkid
-(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that's it.

Vous devez connaître le type de retour de ces éléments de copie et lors de la déclaration du nouvel objet auquel il sera attribué, la valeur de retour doit être immuable ou mutable, sinon le compilateur vous montrera une erreur.

L'objet qui a été copié ne peut pas être modifié avec le nouvel objet, ce sont deux objets totalement différents maintenant.

0
Sauvik Dolui

Assumer 

NSArray *A = xxx; // A with three NSDictionary objects
NSMutableArray *B = [A mutableCopy]; 

Le contenu de B est un objet NSDictionary et non NSMutableDictionary, n'est-ce pas?

0
ZYiOS