2010-01-04 12 views
60

Quelle est la différence entre copy et mutableCopy lorsqu'il est utilisé sur un NSArray ou un NSMutableArray?Comment copy et mutableCopy s'appliquent à NSArray et NSMutableArray?

C'est ce que je comprends. 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 
+1

Vous avez une erreur dans votre édition; sûr que ce soit une faute de frappe ou un malentendu. Dans le premier bloc de code, la variable myArray_imuMuta affectée à mutableCopy est * mutable *, non immuable comme l'indique votre commentaire. –

+0

Merci, c'était une erreur, je me suis trompé avec Xcode en disant "Avertissement NSArray peut ne pas répondre à ajouter -addObject/-removeObjectAtIndex .Je vais changer myArray_imuMuta à NSMutableArray – fuzzygoat

+0

@JamesHarnett - s'il vous plaît arrêter les modifications au nom de" Compatibilité ARC "- voir [cette méta-post] (http://meta.stackoverflow.com/questions/268309/is-it-okay-to-convert-non-arc-objective-c-answers-to-arc) pour – Krease

Répondre

64

copy et mutableCopy sont définis dans des protocoles différents (NSCopying et NSMutableCopying, respectivement), et NSArray est conforme à la fois. mutableCopy est défini pour NSArray (pas seulement NSMutableArray) et vous permet de faire une copie mutable d'un tableau à l'origine 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 NSMutableArray.
  • ne peut pas dépend du résultat de copy pour être modifiable! copy un NSMutableArraypeut renvoyer un NSMutableArray, puisque c'est la classe d'origine, mais copy toute instance arbitraire NSArray ne serait pas.

Edit: relisez votre code d'origine à la lumière de la réponse de Mark Bessey. 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 affecte si le nouveau tableau est modifiable.

Édition 2: Correction de mon hypothèse (fausse) selon laquelle NSMutableArray -copy renverrait un NSMutableArray.

+3

L'envoi d'une copie à un NSMutableArray ne renvoie normalement pas un autre tableau mutable, mais certainement * pourrait le faire *, mais dans le cas habituel, il renvoie un tableau d'accès immuable, à accès constant, –

+0

Oups, vous avez raison. J'ai mal interprété le code de l'OP et je pensais qu'il modifiait le résultat de -copy Il serait tout aussi logique pour -copy de NSMutableArray de retourner un autre tableau mutable, donc j'ai supposé (à tort) que c'était le cas –

+0

I CA ne trouve aucune référence à [mut remove: @ "one"]; cela ne devrait-il pas être [mut removeObjectIdenticalTo: @ "one"]; Je veux juste clarifier pour ceux qui lisent ceci et essayent d'apprendre? – fuzzygoat

8

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 faite, vous pouvez manipuler le contenu de myArray d'origine et ne pas affecter le contenu de myArray_COPY.

Dans le second exemple, vous créez une copie modifiable de myArray, ce qui signifie que vous pouvez modifier l'une ou l'autre copie du tableau, sans affecter l'autre.

Si je change le premier exemple pour essayer d'insérer/supprimer des objets de myArray_COPY, il échoue, comme vous vous en doutez. Peut-être qu'en pensant à un cas d'utilisation typique, cela pourrait aider. Il arrive souvent que vous écriviez une méthode qui prenne un paramètre NSArray * et le stocke pour une utilisation ultérieure. Vous pouvez le faire 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 tableau peut le manipuler entre l'appel de la méthode doStuffLaterWith: et le moment où vous devrez utiliser la valeur ultérieurement. Dans une application multi-thread, le contenu du tableau peut même être modifié pendant que vous parcourez, ce qui peut causer des bugs intéressants.

Si vous faites ce lieu:

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

..then la copie crée un aperçu du contenu du tableau au moment où la méthode est appelée.

6

La méthode "copie" renvoie l'objet créé par la mise en œuvre des protocoles NSCopying copyWithZone:

Si vous envoyez NSString un message de copie:

NSString* myString; 

NSString* newString = [myString copy]; 

La valeur de retour sera un NSString (non mutable)


la méthode mutableCopy renvoie l'objet créé par la mise en oeuvre du protocole mutableCopyWithZone NSMutableCopying:

En envoyant:

NSString* myString; 

NSMutableString* newString = [myString mutableCopy]; 

La valeur de retour SERA être mutable. Dans tous les cas, l'objet doit implémenter le protocole, ce qui signifie qu'il va créer le nouvel objet de copie et vous le renvoyer.


Dans le cas de NSArray, il existe un niveau de complexité supplémentaire en ce qui concerne la copie superficielle et profonde. Une copie superficielle d'un NSArray copie uniquement 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]; 

affectera-t-aussi l'objet à l'index 0 dans le tableau original. Une copie en profondeur copie réellement 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 enlever mon mauvaise hypothèse sur la copie objet mutable

3

Vous appelez addObject et removeObjectAtIndex sur le tableau original, plutôt que la nouvelle copie de celui-ci que vous avez fait. L'appel de copie vs mutableCopy affecte uniquement la mutabilité de la nouvelle copie de l'objet, pas l'objet d'origine.

0

On suppose

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

contenu de B est objet NSDictionary pas NSMutableDictionary, est-il juste?

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

va créer anotherArray qui est une copie de oldArray à 2 niveaux de profondeur. 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 profond vrai Copy nous pourrions utiliser,

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

Cela garantirait que tous les niveaux sont effectivement copiés en conservant la mutabilité de l'objet original à chaque niveau.

Robert Clarence D'Almeida, Bangalore, Inde.

+0

Votre concept de "True Deep Copy" Est vraiment bon .. Exactement ce que je veux ... Merci beaucoup et +1 pour vous ..... –

0
-(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 trucs de copie et en déclarant le nouvel objet que l'on sera attribué la valeur de retour doit être d'un immuable ou mutable, sinon compilateur vous montrer l'erreur.

L'objet qui a été copié ne peut pas être modifié en utilisant le nouveau, ils sont totalement deux objets différents maintenant.

2

Affirmer simplement,

  • copie retourne un immuable (non modifiable) copie du tableau,
  • mutableCopy retourne un mutable (peut être modifié) copie du tableau.

Copie (dans les deux cas) signifie que vous obtenez un nouveau tableau « peuplé » avec des références d'objet dans le tableau d'origine (à savoir les mêmes (objets originaux) sont référencés dans les copies.

Si vous ajoutez 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é de l'original. tableau au moment où la copie a été créée