Existe-t-il une fonction intégrée qui me permet de copier en profondeur un NSMutableArray
?
J'ai regardé autour de moi, certaines personnes disent que cela [aMutableArray copyWithZone:nil]
fonctionne comme une copie profonde. Mais j'ai essayé et cela semble être une copie superficielle.
En ce moment, je fais manuellement la copie avec une for
boucle:
//deep copy a 9*9 mutable array to a passed-in reference array
-deepMuCopy : (NSMutableArray*) array
toNewArray : (NSMutableArray*) arrayNew {
[arrayNew removeAllObjects];//ensure it's clean
for (int y = 0; y<9; y++) {
[arrayNew addObject:[NSMutableArray new]];
for (int x = 0; x<9; x++) {
[[arrayNew objectAtIndex:y] addObject:[NSMutableArray new]];
NSMutableArray *aDomain = [[array objectAtIndex:y] objectAtIndex:x];
for (int i = 0; i<[aDomain count]; i++) {
//copy object by object
NSNumber* n = [NSNumber numberWithInt:[[aDomain objectAtIndex:i] intValue]];
[[[arrayNew objectAtIndex:y] objectAtIndex:x] addObject:n];
}
}
}
}
mais j'aimerais une solution plus propre et plus succincte.
objective-c
cocoa-touch
cocoa
nsarray
deep-copy
Ivan le Terrible
la source
la source
-copy
collections immuables a changé entre Mac OS X 10.4 et 10.5: developer.apple.com/library/mac/releasenotes/Cocoa/… (faites défiler jusqu'à "Collections immuables et comportement de copie")copy
, que doit-on mettre dans la "copie complète"? Si l'élément est une autre collection,copy
ne produit pas réellement une copie (de la même classe). Je pense donc qu'il est parfaitement valable d'argumenter sur le type de copie souhaité dans le cas particulier.NSCopying
/-copy
, alors il n'est pas copiable - vous ne devriez donc jamais essayer d'en faire une copie, car ce n'est pas une capacité pour laquelle il a été conçu. En termes d'implémentation de Cocoa, les objets non copiables ont souvent un état de backend C auquel ils sont liés, donc le piratage d'une copie directe de l'objet peut conduire à des conditions de concurrence ou pire. Donc, pour répondre «ce qui doit être mis dans la« copie profonde »» - Une réf. La seule chose que vous pouvez mettre n'importe où quand vous avez un non-NSCopying
objet.Réponses:
Comme l' indique explicitement la documentation Apple sur les copies complètes:
Le code ci-dessus crée un nouveau tableau dont les membres sont des copies superficielles des membres de l'ancien tableau.
Notez que si vous devez copier en profondeur une structure de données imbriquée entière - ce que les documents Apple liés appellent une véritable copie profonde - alors cette approche ne suffira pas. Veuillez consulter les autres réponses ici pour cela.
la source
copyWithZone:
est implémentée sur la classe de réception.La seule façon que je connais de le faire facilement est d'archiver puis de désarchiver immédiatement votre tableau. Cela ressemble un peu à un hack, mais est en fait explicitement suggéré dans la documentation Apple sur la copie de collections , qui stipule:
Le hic, c'est que votre objet doit prendre en charge l'interface NSCoding, car elle sera utilisée pour stocker / charger les données.
Version Swift 2:
la source
initWithArray:copyItems:
méthode? Cette solution de contournement d'archivage / désarchivage semble très utile, compte tenu du nombre de classes de contrôle conformes à NSCoding mais pas à NSCopying.La copie par défaut donne une copie superficielle
En effet, l'appel
copy
est le même quecopyWithZone:NULL
celui de la copie avec la zone par défaut. L'copy
appel n'entraîne pas une copie complète. Dans la plupart des cas, cela vous donnerait une copie superficielle, mais dans tous les cas cela dépend de la classe. Pour une discussion approfondie, je recommande les rubriques de programmation des collections sur le site Apple Developer.initWithArray: CopyItems: donne une copie profonde à un niveau
NSCoding
est le moyen recommandé par Apple pour fournir une copie complètePour une véritable copie profonde (Array of Arrays), vous aurez besoin
NSCoding
et archiver / désarchiver l'objet:la source
Pour Dictonary
NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);
Pour Array
NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);
la source
Non, il n'y a pas quelque chose de intégré dans les cadres pour cela. Les collections Cocoa prennent en charge les copies superficielles (avec les méthodes
copy
ouarrayWithArray:
) mais ne parlent même pas d'un concept de copie profonde.Cela est dû au fait que la "copie complète" commence à devenir difficile à définir lorsque le contenu de vos collections commence à inclure vos propres objets personnalisés. La «copie profonde» signifie-t-elle que chaque objet du graphe d'objets est une référence unique par rapport à chaque objet du graphe d'objets d'origine?
S'il y avait un
NSDeepCopying
protocole hypothétique , vous pourriez le configurer et prendre des décisions dans tous vos objets, mais malheureusement il n'y en a pas. Si vous contrôliez la plupart des objets de votre graphique, vous pouvez créer vous-même ce protocole et l'implémenter, mais vous devrez ajouter une catégorie aux classes Foundation si nécessaire.La réponse de @ AndrewGrant suggérant l'utilisation de l'archivage / désarchivage par clé est un moyen non performant mais correct et propre d'y parvenir pour des objets arbitraires. Ce livre va même jusqu'à présent, alors suggérez d' ajouter une catégorie à tous les objets qui fait exactement cela pour prendre en charge la copie profonde.
la source
J'ai une solution de contournement si j'essaie d'obtenir une copie complète pour les données compatibles JSON.
Il suffit
NSData
d'NSArray
utiliserNSJSONSerialization
et de recréer l'objet JSON, cela créera une nouvelle et nouvelle copie complète deNSArray/NSDictionary
avec de nouvelles références de mémoire.Mais assurez-vous que les objets de NSArray / NSDictionary et leurs enfants doivent être sérialisables JSON.
la source
NSJSONReadingMutableContainers
le cas d'utilisation dans cette question.