Gibt es eine eingebaute Funktion, mit der ich eine tief kopieren kann NSMutableArray
?
Ich habe mich umgesehen, manche Leute sagen, es [aMutableArray copyWithZone:nil]
funktioniert als tiefe Kopie. Aber ich habe es versucht und es scheint eine flache Kopie zu sein.
Im Moment mache ich das Kopieren manuell mit einer for
Schleife:
//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];
}
}
}
}
aber ich hätte gerne eine sauberere, prägnantere Lösung.
objective-c
cocoa-touch
cocoa
nsarray
deep-copy
Ivan der Schreckliche
quelle
quelle
-copy
unveränderlichen Sammlungen zwischen Mac OS X 10.4 und 10.5 geändert hat: developer.apple.com/library/mac/releasenotes/Cocoa/… (scrollen Sie nach unten zu "Unveränderliche Sammlungen und Kopierverhalten")copy
, was soll in die "tiefe Kopie" eingefügt werden? Wenn das Element eine andere Sammlung ist,copy
wird tatsächlich keine Kopie (derselben Klasse) ausgegeben. Ich denke, es ist absolut richtig, über die Art der Kopie zu streiten, die im konkreten Fall gewünscht wird.NSCopying
/ nicht implementiert-copy
, kann es nicht kopiert werden. Sie sollten daher niemals versuchen, eine Kopie davon zu erstellen , da dies keine Funktion ist, für die es entwickelt wurde. In Bezug auf die Implementierung von Cocoa haben nicht kopierbare Objekte häufig einen C-Backend-Status, an den sie gebunden sind. Das Hacken einer direkten Kopie des Objekts kann daher zu Rennbedingungen oder schlechteren Bedingungen führen. Um zu antworten: "Was soll in die" tiefe Kopie "gelegt werden ?" Das einzige, was Sie irgendwo platzieren können, wenn Sie ein Nicht-NSCopying
Objekt haben.Antworten:
In der Apple-Dokumentation zu Deep Copies heißt es ausdrücklich:
Der obige Code erstellt ein neues Array, dessen Mitglieder flache Kopien der Mitglieder des alten Arrays sind.
Beachten Sie, dass dieser Ansatz nicht ausreicht , wenn Sie eine gesamte verschachtelte Datenstruktur tief kopieren müssen - was in den verknüpften Apple-Dokumenten als echte tiefe Kopie bezeichnet wird. Bitte beachten Sie die anderen Antworten hier.
quelle
copyWithZone:
sie in der empfangenden Klasse implementiert ist.Die einzige Möglichkeit, die ich kenne, besteht darin, Ihr Array zu archivieren und dann sofort wieder zu archivieren. Es fühlt sich ein bisschen wie ein Hack, aber tatsächlich explizit in der vorgeschlagenen Apple - Dokumentation über das Kopieren von Sammlungen , die besagt:
Der Haken ist, dass Ihr Objekt die NSCoding-Schnittstelle unterstützen muss, da diese zum Speichern / Laden der Daten verwendet wird.
Swift 2 Version:
quelle
initWithArray:copyItems:
Methode verwendete NSCopying ? Diese Problemumgehung für das Archivieren / Aufheben der Archivierung scheint sehr nützlich zu sein, wenn man bedenkt, wie viele Steuerungsklassen der NSCoding, aber nicht der NSCopying entsprechen.Standardmäßig kopieren ergibt eine flache Kopie
Dies liegt daran, dass das Aufrufen
copy
dasselbe ist wiecopyWithZone:NULL
das Kopieren mit der Standardzone. Dercopy
Anruf führt nicht zu einer tiefen Kopie. In den meisten Fällen erhalten Sie eine flache Kopie, die jedoch in jedem Fall von der Klasse abhängt. Für eine gründliche Diskussion empfehle ich die Sammlungsprogrammierungsthemen auf der Apple Developer-Website.initWithArray: CopyItems: Gibt eine einstufige tiefe Kopie
NSCoding
ist die von Apple empfohlene Methode, um eine tiefe Kopie bereitzustellenFür eine echte Deep Copy (Array of Arrays) benötigen
NSCoding
Sie das Objekt und archivieren / entarchivieren es:quelle
Für Diktonar
NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);
Für Array
NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);
quelle
Nein, dafür ist nichts in die Frameworks eingebaut. Kakaosammlungen unterstützen flache Kopien (mit dem
copy
oder demarrayWithArray:
Methoden), sprechen jedoch nicht einmal über ein Deep-Copy-Konzept.Dies liegt daran, dass die Definition von "Deep Copy" immer schwieriger wird, wenn der Inhalt Ihrer Sammlungen einschließlich Ihrer eigenen benutzerdefinierten Objekte beginnt. Bedeutet "Deep Copy", dass jedes Objekt im Objektdiagramm eine eindeutige Referenz in Bezug auf jedes Objekt im ursprünglichen Objektdiagramm ist?
Wenn es eine hypothetische gab
NSDeepCopying
Protokoll , könnten Sie dieses einrichten und Entscheidungen in all Ihren Objekten treffen, aber leider nicht. Wenn Sie die meisten Objekte in Ihrem Diagramm gesteuert haben, können Sie dieses Protokoll selbst erstellen und implementieren, müssen jedoch den Foundation-Klassen nach Bedarf eine Kategorie hinzufügen.Die Antwort von @ AndrewGrant, die die Verwendung von Archivierung / Archivierung ohne Schlüssel vorschlägt, ist eine nicht leistungsfähige, aber korrekte und saubere Methode, um dies für beliebige Objekte zu erreichen. Dieses Buch geht sogar so weit, also schlagen Sie vor , allen Objekten eine Kategorie hinzuzufügen, die genau das tut, um das Tiefenkopieren zu unterstützen.
quelle
Ich habe eine Problemumgehung, wenn ich versuche, eine tiefe Kopie für JSON-kompatible Daten zu erhalten.
Nehmen Sie einfach
NSData
dieNSArray
VerwendungNSJSONSerialization
und dann JSON - Objekt erstellen, das wird eine ganz neue und frische Kopie erstellenNSArray/NSDictionary
mit neuen Speicherreferenzen von ihnen.Stellen Sie jedoch sicher, dass die Objekte von NSArray / NSDictionary und ihre untergeordneten Objekte JSON-serialisierbar sind.
quelle
NSJSONReadingMutableContainers
für den Anwendungsfall in dieser Frage angeben .