Czy jest jakaś wbudowana funkcja, która pozwala mi głęboko skopiować plik NSMutableArray
?
Rozejrzałem się, niektórzy mówią, że [aMutableArray copyWithZone:nil]
działa jak głęboka kopia. Ale próbowałem i wydaje się, że jest to płytka kopia.
W tej chwili ręcznie wykonuję kopię z for
pętlą:
//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];
}
}
}
}
ale chciałbym uzyskać czystsze, bardziej zwięzłe rozwiązanie.
objective-c
cocoa-touch
cocoa
nsarray
deep-copy
ivanTheTerrible
źródło
źródło
-copy
niezmiennych kolekcji zmieniło się między Mac OS X 10.4 i 10.5: developer.apple.com/library/mac/releasenotes/Cocoa/ ... (przewiń w dół do „Niezmienne kolekcje i zachowanie kopiowania”)copy
, co należy umieścić w „głębokiej kopii”? Jeśli element jest inną kolekcją, wcopy
rzeczywistości nie daje kopii (tej samej klasy). Dlatego uważam, że spór o rodzaj kopii, jaki ma być w konkretnym przypadku, jest całkowicie zasadny.NSCopying
/-copy
, to nie można go skopiować - więc nigdy nie powinieneś próbować tworzyć jego kopii, ponieważ nie jest to zdolność, do której został zaprojektowany. Jeśli chodzi o implementację Cocoa, obiekty nie do skopiowania często mają stan zaplecza C, z którym są powiązane, więc hakowanie bezpośredniej kopii obiektu może prowadzić do warunków wyścigu lub gorzej. Tak więc odpowiadając „co należy umieścić w„ głębokiej kopii ”” - zachowany ref. Jedyną rzeczą, którą możesz umieścić w dowolnym miejscu, gdy maszNSCopying
obiekt niebędący przedmiotem.Odpowiedzi:
Jak wyraźnie stwierdza dokumentacja Apple dotycząca głębokich kopii :
Powyższy kod tworzy nową tablicę, której elementy członkowskie są płytkimi kopiami elementów starej tablicy.
Zwróć uwagę, że jeśli chcesz głęboko skopiować całą zagnieżdżoną strukturę danych - to, co połączone dokumenty Apple nazywają prawdziwą głęboką kopią - to podejście nie wystarczy. Zobacz inne odpowiedzi tutaj.
źródło
copyWithZone:
jest zaimplementowana w klasie odbierającej.Jedyny sposób, w jaki mogę to łatwo zrobić, to zarchiwizować, a następnie natychmiast cofnąć archiwizację tablicy. Wydaje się, że to trochę włamania, ale w rzeczywistości jest wyraźnie sugerowane w dokumentacji Apple dotyczącej kopiowania kolekcji , która stwierdza:
Problem polega na tym, że obiekt musi obsługiwać interfejs NSCoding, ponieważ będzie on używany do przechowywania / ładowania danych.
Wersja Swift 2:
źródło
initWithArray:copyItems:
metodzie? To obejście archiwizacji / przywracania archiwizacji wydaje się bardzo przydatne, biorąc pod uwagę, ile klas kontrolnych jest zgodnych z NSCoding, ale nie z NSCopying.Kopiuj domyślnie daje płytką kopię
Dzieje się tak, ponieważ dzwonienie
copy
jest tym samym, cocopyWithZone:NULL
nazywamy kopiowaniem ze strefą domyślną.copy
Wywołanie nie powoduje głębokiej kopii. W większości przypadków dałoby to płytką kopię, ale w każdym razie zależy to od klasy. Aby uzyskać dokładną dyskusję, polecam tematy dotyczące programowania kolekcji w witrynie Apple Developer.initWithArray: CopyItems: daje jednopoziomową głęboką kopię
NSCoding
jest zalecanym przez Apple sposobem dostarczania głębokiej kopiiAby uzyskać prawdziwie głęboką kopię (Array of Arrays), będziesz potrzebować
NSCoding
i zarchiwizować / cofnąć archiwizację obiektu:źródło
Dla Dictonary
NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);
Dla Array
NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);
źródło
Nie, nie ma czegoś wbudowanego w ramy tego. Kolekcje Cocoa obsługują płytkie kopie ( metodami
copy
lubarrayWithArray:
), ale nawet nie wspominają o koncepcji głębokiego kopiowania.Dzieje się tak, ponieważ „głęboka kopia” zaczyna być trudna do zdefiniowania, gdy zawartość kolekcji zaczyna zawierać własne obiekty niestandardowe. Czy „głęboka kopia” oznacza, że każdy obiekt w grafie obiektów jest unikalnym odniesieniem do każdego obiektu w oryginalnym grafie obiektów?
Gdyby istniał jakiś hipotetyczny
NSDeepCopying
protokół, mógłbyś go ustawić i podejmować decyzje we wszystkich swoich obiektach, ale niestety tak nie jest. Jeśli kontrolujesz większość obiektów na swoim wykresie, możesz sam stworzyć ten protokół i zaimplementować go, ale w razie potrzeby musisz dodać kategorię do klas Foundation.Odpowiedź @AndrewGranta sugerująca użycie archiwizacji / przywracania z archiwum z kluczem jest nieefektywnym, ale poprawnym i czystym sposobem osiągnięcia tego dla dowolnych obiektów. Ta książka posuwa się nawet tak daleko, że sugeruje dodanie kategorii do wszystkich obiektów, która robi dokładnie to, aby wspierać głębokie kopiowanie.
źródło
Mam obejście, jeśli próbuję uzyskać głęboką kopię danych zgodnych z formatem JSON.
Wystarczy wziąć
NSData
zNSArray
użyciemNSJSONSerialization
, a następnie odtworzyć obiekt JSON, to stworzy zupełnie nową i świeżą kopięNSArray/NSDictionary
z nowych referencji pamięć o nich.Ale upewnij się, że obiekty NSArray / NSDictionary i ich elementy podrzędne muszą być serializowane w formacie JSON.
źródło
NSJSONReadingMutableContainers
dla przypadku użycia w tym pytaniu.