2013-03-23 6 views
8

Ho un NSDictionary che contiene istanze di molti tipi di oggetti diversi (NSArrays, NSDictionaries, NSStrings, NSNumbers, ecc.). Molti degli NSDictionaries e NSStrings hanno il proprio nidificato NSDictionaries e NSArrays.Come eseguire il ciclo attraverso una gerarchia nidificata di NSDictionaries e NSArrays e convertire tutti in copie mutabili?

come posso ciclo attraverso l'intera gerarchia, da cima a fondo, e convertire tutte le istanze di NSDictionaries e NSArrays rispettivamente NSMutableDictionaries e NSMutableArrays,?

Esiste una funzione "ricorsiva di copie mutevoli" facile da ignorare? In caso contrario, devo semplicemente ripetere e controllare ripetutamente? Posso semplicemente sostituire mentre vado o devo ricostruire l'intera gerarchia?

risposta

18

Il metodo seguente crea una copia mutabile (profonda) annidata di array, dizionari e insiemi nidificati. Può anche essere usato per creare copie mutabili di oggetti non di raccolta all'interno della gerarchia, come le stringhe.

@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 

Usalo come

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

(chiavi dei dizionari non vengono copiati, solo i valori).

Sono abbastanza sicuro di aver visto qualcosa di simile su SO, ma non riesco a trovarlo adesso.

+0

Cosa intendi con "chiavi non copiate"? – zakdances

+1

@yourfriendzak: Per un dizionario '@ {chiave: valore}' il mio codice creerebbe '@ {chiave: mutableCopyOfValue}', e non '@ {mutableCopyOfKey: mutableCopyOfValue}'. Nella maggior parte dei casi, le chiavi sono stringhe costanti, quindi non ha senso copiarle. –

+0

@yourfriendzak: in realtà questo codice fa più di quanto richiesto. Rende le copie mutabili dove mai possibile, ad esempio le copie mutevoli delle stringhe nella gerarchia. Se questo non è voluto, posso modificare il codice. –

1

Per il NSDictionary esterno, questo creerà per 1 livello inferiore.

È necessario chiamare questo in un metodo e andare a ottenere tutti i dict e array.

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]; 
    } 
} 

Non compilato. Leggi come algoritmo

+0

Perché non scrivere questo come metodo ricorsivo? –

2

Mentre la risposta di Anoop va bene (credo, non l'ho compilata neanche), se la gerarchia delle istanze è in realtà un elenco di proprietà, è possibile utilizzare NSPropertyListSerialization per deserializzare un plist con contenitori e/o fogliabili i nodi.

Questo ridurrebbe a un numero inferiore di righe di codice e probabilmente sarebbe più veloce di una discesa manuale attraverso il grafico degli oggetti, ma questa soluzione ha senso solo se inizialmente si deserializza il plist da qualche parte.

+1

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

+1

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

1

Se è stato utilizzato un metodo del sistema operativo per creare il dizionario: questi metodi hanno spesso un parametro che consente di creare oggetti mutabili. Ad esempio, la classe serializzatore JSON ha flag per rendere tutti i dizionari e gli array mutabili e per rendere tutti gli oggetti NSString mutabili (NSNumber e NSNull non sono mai mutabili).

Problemi correlati