2013-03-23 5 views
8

Ich habe eine NSDictionary, die Instanzen von vielen verschiedenen Arten von Objekten enthält (NSArrays, NSDictionaries, NSStrings, NSNumbers, etc ...). Viele der NSDictionaries und NSStrings haben ihre eigenen verschachtelten NSDictionaries und NSArrays.Wie durchläuft man eine verschachtelte Hierarchie von NSDictionaries und NSArrays und konvertiert alle in veränderbare Kopien?

Wie kann ich Schleife durch die gesamte Hierarchie von oben nach unten, und konvertieren Sie alle Instanzen von NSDictionaries und NSArrays-NSMutableDictionaries und NSMutableArrays jeweils?

Gibt es eine einfache "rekursiv machbare Kopien" -Funktion, von der ich nichts weiß? Wenn nicht, muss ich nur wiederholen Schleife und wiederholen Sie die Prüfung? Kann ich einfach ersetzen, wie ich gehe oder habe ich die gesamte Hierarchie neu erstellt?

Antwort

18

Die folgende Methode erstellt eine verschachtelte (tief) veränderbare Kopie verschachtelter Arrays, Wörterbücher und Mengen. Es kann auch verwendet werden, um veränderbare Kopien von Nicht-Sammlungsobjekten innerhalb der Hierarchie zu erstellen, z. B. Strings.

@interface NSObject (MyDeepCopy) 
-(id)deepMutableCopy; 
@end 

@implementation NSObject (MyDeepCopy) 
-(id)deepMutableCopy 
{ 
    if ([self isKindOfClass:[NSArray class]]) { 
     NSArray *oldArray = (NSArray *)self; 
     NSMutableArray *newArray = [NSMutableArray array]; 
     for (id obj in oldArray) { 
      [newArray addObject:[obj deepMutableCopy]]; 
     } 
     return newArray; 
    } else if ([self isKindOfClass:[NSDictionary class]]) { 
     NSDictionary *oldDict = (NSDictionary *)self; 
     NSMutableDictionary *newDict = [NSMutableDictionary dictionary]; 
     for (id obj in oldDict) { 
      [newDict setObject:[oldDict[obj] deepMutableCopy] forKey:obj]; 
     } 
     return newDict; 
    } else if ([self isKindOfClass:[NSSet class]]) { 
     NSSet *oldSet = (NSSet *)self; 
     NSMutableSet *newSet = [NSMutableSet set]; 
     for (id obj in oldSet) { 
      [newSet addObject:[obj deepMutableCopy]]; 
     } 
     return newSet; 
#if MAKE_MUTABLE_COPIES_OF_NONCOLLECTION_OBJECTS 
    } else if ([self conformsToProtocol:@protocol(NSMutableCopying)]) { 
      // e.g. NSString 
     return [self mutableCopy]; 
    } else if ([self conformsToProtocol:@protocol(NSCopying)]) { 
      // e.g. NSNumber 
     return [self copy]; 
#endif 
    } else { 
     return self; 
    } 
} 
@end 

Verwenden Sie es wie

NSDictionary *dict = ...; 
NSMutableDictionary *mdict = [dict deepMutableCopy]; 

(Dictionary Schlüssel nicht kopiert, sondern nur die Werte).

Ich bin mir ziemlich sicher, dass ich sowas auf SO gesehen habe, aber es jetzt nicht finden kann.

+0

Was meinen Sie "Schlüssel werden nicht kopiert"? – zakdances

+1

@yourfriendzak: Für ein Wörterbuch '@ {key: value}' würde mein Code '@ {key: mutableCopyOfValue}' und nicht '@ {mutableCopyOfKey: mutableCopyOfValue}} erzeugen. Keys sind in den meisten Fällen konstante Strings, so dass es nicht sinnvoll ist, sie zu kopieren. –

+0

@yourfriendzak: Tatsächlich macht dieser Code mehr als Sie benötigen. Es macht veränderbare Kopien, wo immer es möglich ist, zum Beispiel veränderbare Kopien von Strings in der Hierarchie. Wenn das nicht gewünscht wird, kann ich den Code ändern. –

1

Für das äußere NSDictionary wird dies für 1-Level-Down erstellen.

Sie müssen dies in einer Methode aufrufen, und gehen Sie weiter, um alle dict und array zu erhalten.

NSMutableDictionary *dict=[NSMutableDictionary new]; 
NSMutableArray *array=[NSMutableArray new]; 

for(NSDictionary *dict in yourMainDictionary){ 
    if([outerDict[dict] class]==[NSDictionary class]){ 
     [dict setObject:outerDict[dict] forKey:dict]; 
    } 
    else if([outerDict[dict] class]==[NSArray class]){ 
     array[array.count]=outerDict[dict]; 
    } 
} 

Compiler nicht überprüft. Als Algorithmus lesen

+0

Warum schreiben Sie das nicht als rekursive Methode? –

2

Während Antwort Anoop das ist gut so (wie ich glaube, ich es auch nicht kompilieren hat), wenn Ihre Hierarchie der Instanzen tatsächlich eine Eigenschaftsliste ist, dann können Sie NSPropertyListSerialization verwenden, um eine plist mit wandelbaren Containern und/oder Blatt deserialisieren Knoten.

Dies würde sich auf weniger Codezeilen reduzieren und wahrscheinlich schneller sein als ein manueller Abstieg durch das Objektdiagramm, aber diese Lösung macht nur dann Sinn, wenn Sie das Plist von irgendwo deserialisieren.

+1

NSMutableArray * newArray = (NSMutableArray *) CFBridgingRelease (CFPropertyListCreateDeepCopy (kCFAllocatorDefault, (CFArrayRef) originalArray, kCFPropertyListMutableContainers)); – nh32rg

+1

NSMutableDictionary * newDict = (NSMutableDictionary *) CFBridgingRelease (CFPropertyListCreateDeepCopy (kCFAllocatorDefault, (CFDictionaryRef) originalDict, kCFPropertyListMutableContainers)); – nh32rg

1

Wenn Sie eine Betriebssystemmethode verwendet haben, um das Wörterbuch zu erstellen: Diese Methoden haben oft einen Parameter, mit dem Sie änderbare Objekte erstellen können. Die JSON-Serialiser-Klasse verfügt beispielsweise über Flags, um alle Wörterbücher und Arrays veränderbar zu machen und um alle NSString-Objekte veränderbar zu machen (NSNumber und NSNull sind niemals veränderbar).

Verwandte Themen