11
votes

Copier un nsarray avec des copies mutables des éléments d'origine

Je crée une gamme de dictionnaires dans une classe. Je veux revenir une copie de ce tableau à tout autre objet qui le demande. Cette copie qui est transmise à d'autres objets doit être modifiée sans modifier l'original.

Je utilise donc ce qui suit dans une méthode getter de ma classe qui contient le tableau "Master": P>

[[NSMutableArray alloc] initWithArray:masterArray copyItems:YES];


0 commentaires

4 Réponses :


6
votes

Copier un tableau créera une copie de l'objet Array, avec des références aux objets de contenu d'origine (conservés correctement.)

par la documentation, -Initwitharray: CopyItems: initialise le nouveau tableau avec copies des éléments du tableau d'origine. Cette copie est créée en envoyant les objets de contenu d'origine -Copywithzone: , qui créera une copie immuable dans le cas d'objets mutables.

Si vous avez besoin d'un comportement différent (c'est-à-dire des copies mutables des objets de contenu ou des copies profondes des objets de contenu), vous devrez écrire votre propre fonction / méthode de commodité pour le faire.


2 commentaires

C'était une modification vraiment inane quinn. Il est parfaitement acceptable de compenser cette phrase avec des virgules comme dans l'original. Si vous allez être une grammaire nazie, vous avez toujours besoin d'une virgule après le "I.e.", même à l'intérieur des parenthèses.


Ne pas mentionner l'une après la parenthèse. Mais oui, chaque édition est une étape vers la publication de la post de la communauté-wiki-wiki '( Stackoverflow.com/questions/128434/... ), alors ne les gaspillons pas sur" Fixer "la grammaire" d'autres ", à la seule exception de restauré numériquement un post par ailleurs illisible.



2
votes

Jim est correct sur -Initwitharray: copyItems code> Envoi d'un -Copywithzone: code> message à chaque élément . Pour obtenir des copies mutables des éléments de tableau, vous auriez besoin d'envoyer -mutablecopywithzone: code> (ou juste -MutableCopy code> pour brièveté) à chaque élément. C'est assez simple: xxx pré>

Cependant, il existe une question plus profonde masquée dans votre explication du problème: il semble que vous souhaitiez que la matrice et ses éléments (dictionnaires) soient mutables, mais là sont quelques points fins qui devraient être effacés, en particulier à la lumière de votre stipulation que "[la copie transmise à d'autres objets doit être modifiée sans modifier l'original." EM> en fonction de ce que Vous voulez dire, cela peut être assez complexe à garantir et à mettre en œuvre. p>

Par exemple, supposons que le tableau d'origine contienne un certain nombre de dictionnaires mutables. Créer des copies mutables de ces deux premiers niveaux signifie que quelqu'un qui obtient une copie peut modifier leur propre tableau et leurs dictionnaires dans le tableau sans modifier directement le tableau d'origine ni le dictionnaire. Toutefois, si un dictionnaire contient des objets mutables (comme un nsmutableArraRray, NsMutableString, etc.), le code utilisant la "copie" pourrait modifier le contenu du dictionnaire indirectement, en utilisant uniquement une référence à la copie mutable. P>

Les copies mutables sont "peu profondes", ce qui signifie que le premier niveau est copié et la copie a des pointeurs vers les mêmes éléments que la structure d'origine. Ainsi, garantissant qu'il n'y a pas de liaison entre l'original et la copie (au moins, manuellement) nécessiterait un balayage à travers toute la structure et faire des copies. Cela peut devenir plus compliqué si certains éléments ne sont pas conformes à NScopying ou à NsmutableCopying. P>

La solution la plus facile et la plus rapide consiste à utiliser le code simple ci-dessus ou à renvoyer une référence à la matrice maître. Cela nécessite de faire confiance à ce que le code client ne modifie pas la matrice, cela peut donc ne pas fonctionner dans toutes les situations, mais si vous contrôlez également le code d'appel, cela peut être préférable. D'autre part, si vous voulez absolument une copie totalement séparée, envisagez d'utiliser NSCODING / Archivage à saisir: P>

NSMutableArray *masterArray = ...
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:masterArray];
NSMutableArray *clone = [NSKeyedUnarchiver unarchiveObjectWithData:data];


0 commentaires

5
votes

Une manière d'abuser du codage de la valeur de clé pour envoyer mutablecopy à chacun des dictionnaires et AutoRelease à chacun des copies. Mais c'est un hack sale et sale, alors ne le faites pas. En effet, vous ne devriez probablement pas faire cela en premier lieu.

En règle générale, lorsque je vois les mots "gamme de dictionnaires", je reçois l'idée que vous utilisez des dictionnaires comme substituts des objets de modèle. Ne fais pas ça. Écrivez vos propres classes de modèle; Tout devient beaucoup plus facile lorsque vous avez vos propres propriétés personnalisées et méthodes de comportement pour travailler. (Certaines choses plus que d'autres: la mise en œuvre du support AppleScript est pratiquement impossible sans une couche de modèle appropriée.)

et une fois que vous avez de vrais objets de modèle, vous pouvez implémenter nscopying et ne pas avoir besoin de vous inquiéter de mutable versus immuable, car vous n'aurez probablement pas une distinction mutabilité dans vos véritables classes de modèle . (Je ne connais pas les autres, mais je n'ai jamais fait une telle distinction dans mes classes de modèle.) Ensuite, vous pouvez simplement utiliser le NSARRAY INITWITHARRAY: COPYITEMS: .


2 commentaires

EW EW EW, s'il vous plaît, ne mentionnez même pas de choses comme utiliser -valueforkey: de cette façon où les débutants peuvent voir et être induit en erreur. (Ils le savent, vous savez: "Sur Internet, j'ai lu la manière de faire des copies mutables était ..." Est-ce que cela se souviendra de.)


J'ai changé que le paragraphe sera moins spécifique et de recommander plus fortement à ce sujet. Que pensez-vous maintenant?



14
votes

Une autre approche que vous puissiez prendre consiste à utiliser la fonction CFPropertylistylistTreateDeePopopyCopopy () (dans le cadre de base de fondation), en passant dans kcfpropertylistmutablecontainers pour l'argument mutableOption. Le code ressemblerait à:

NSMutableArray* originalArray;
NSMutableArray* newArray;

newArray = (NSMutableArray*)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFPropertyListRef)originalArray, kCFPropertyListMutableContainers);


1 commentaires

Tout comme n'importe quelle autre fonction de base de base qui fait une "Création" ou "Copie", vous êtes responsable de la libération de la valeur renvoyée une fois que vous avez terminé.