2013-04-16 15 views
6

Sto provando a stampare una struttura JSON oggettivata che sto salvando in più dizionari in una gerarchia. Mi piacerebbe farlo attraverso il metodo description di NSObject in modo che il metodo di descrizione di ogni dizionario annidato venga chiamato a restituire anche il suo valore.Nested NSDictionary Descrizione Escape Character Problemi

Risultato desiderato

 //First Hierarchal Level 
       //Second Hierarchal Level 
         //Third Hierarchal Level 
People = 
(
    { 
     Name = Person 1 
     Gender = Male 
     Addresses = 
     ( 
      { 
       Address Name = Home Address 
       Street = 123 Street St. 
       City = NewCity 
       State = AZ 
       Zip = 12345 
       Country = USA 
      } 
     ) 
     Cars = 
     ( 
      { 
       Make = Ford 
       Model = NewFord 
       Insured Drivers = 
       (
        { 
         Name = Person 1 
        }, 
        { 
         Name = Person 2 
        } 
       ) 
      } 
     ) 
    } 
) 

//NOTE: Sample untested nested structure 

Tuttavia, Sono stato in esecuzione in un problema che la stringa di ritorno per ogni dizionario nidificato è sempre sfuggito una volta per ogni livello della gerarchia che la stringa di ritorno viene passato attraverso.

risultato effettivo

People = \n (\n {\n Name = Person 1\\\n Gender = Male\\\n Addresses =\\\n (\\\n {\\\n Address Name = Home Address\\\n Street = 123 Street St.\\\n City = NewCity\\\n State = AZ\\\n Zip = 12345\\\n Country = USA\\\n }\\\n)\\\n Cars = \\\n (\\\n {\\\\\\\n Make = Ford\\\\\\\n Model = NewFord\\\\\\\n Insured Drivers = \\\\\\\n (\\\\\\\n {\\\\\\\\\\\\\n Name = Person 1\\\\\\\\\\\\\n },\\\\\\\\\\\\\n {\\\\\\\\\\\\\n Name = Person 2\\\\\\\\\\\\\n }\\\\\\\n)\\\\\\\n }\\\n) \n }\n) 

Ho letto che questo ha a che fare con il modo descrizione aggiunge questi caratteri di escape a causa di essa usando qualcosa come un programma di utilità syslog, tuttavia credo la funzionalità che desidero è disponibile a causa di come NSArray descrive i suoi contenuti in modo simile al modo in cui mi piacerebbe. Ho provato a ripetere la stringa dei risultati e ad analizzare i caratteri di escape, ma finora il risultato migliore che ho ottenuto è un elenco non gerarchico di tutte le proprietà in tutti i dizionari.

miglior tentativo

People = 
(
{ 
Name = Person 1 
Gender = Male 
Addresses = 
( 
{ 
Address Name = Home Address 
Street = 123 Street St. 
City = NewCity 
State = AZ 
Zip = 12345 
Country = USA 
} 
) 
Cars = 
( 
{ 
Make = Ford 
Model = NewFord 
Insured Drivers = 
(
{ 
Name = Person 1 
}, 
{ 
Name = Person 2 
} 
) 
} 
) 
} 
) 

Mi chiedevo se qualcun altro ha incontrato questo problema e come hanno superato esso.

Qualsiasi e tutti i suggerimenti sono benvenuti. Grazie per la ricerca.

UPDATE 1: Come per i consigli nei commenti, ho cercato parsing miei oggetti dizionario alle stringhe JSON per la stampa utilizzando il seguente metodo categoria NSDictionary:

-(NSString*)JSONDescription 
{ 
    NSError *error; 
    NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:&error]; 
    NSString* json = nil; 

    if (! jsonData) { 
     NSLog(@"WARNING: NSDictionary JSONDescription encountered error \"%@\"", error); 
    } else { 
     json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 
    } 

    return json; 
} 

Poi, ad ogni livello della mia gerarchia, sto chiamando il mio oggetto dizionario JSONDescription in ogni metodo description. Tuttavia, non sembra che venga chiamato il metodo description dell'oggetto nidificato. Ciò causa la seguente eccezione:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Address)' 

Esempio Attuazione

#import "Person.h" 

#define NAME @"Name" 
#define GENDER @"Gender" 
#define ADDRESSES @"Addresses" 
#define CARS @"Cars" 

@implementation Person 

-(NSDictionary*)toDictionary{ 
    return @{ NAME: self.name, 
       GENDER: self.gender, 
       ADDRESSES: self.addresses, 
       CARS: self.cars}; 
} 

-(NSString*)description{ 
    return self.toDictionary.JSONDescription; 
} 

@end 


#import "Address.h" 

#define ADDRESS_NAME @"Address Name" 
#define STREET @"Street" 
#define CITY @"City" 
#define STATE @"State" 
#define ZIP @"Zip" 
#define COUNTRY @"Country" 

@implementation Address 

-(NSDictionary*)toDictionary{ 
    return @{ ADDRESS_NAME: self.addressName, 
       STREET: self.street, 
       CITY: self.city, 
       STATE: self.state, 
       ZIP: self.zip, 
       COUNTRY: self.country}; 
} 

-(NSString*)description{ 
    return self.toDictionary.JSONDescription; 
} 

@end 


#import "Car.h" 

#define MAKE @"Make" 
#define MODEL @"Model" 
#define INSURED_DRIVERS @"Insured Drivers" 

@implementation Car 

-(NSDictionary*)toDictionary{ 
    return @{ MAKE: self.make, 
       MODEL: self.model, 
       INSURED_DRIVERS: self.drivers}; 
} 

-(NSString*)description{ 
    return self.toDictionary.JSONDescription; 
} 

@end 


#import "Driver.h" 

#define NAME @"Name" 

@implementation Car 

-(NSDictionary*)toDictionary{ 
    return @{ NAME: self.name}; 
} 

-(NSString*)description{ 
    return self.toDictionary.JSONDescription; 
} 

@end 
+0

Sono un po 'confuso perché a volte si mostra "chiave = valore" (come in un dizionario) e, talvolta, "chiave: il valore" (come in JSON) nei tuoi esempi.Quale vuoi nell'output? - E puoi mostrare il tuo codice che ha prodotto il "miglior tentativo"? –

+0

Ah si. Grazie. Ho risolto l'esempio. Mentre ovviamente vorrei che fossero coerenti, o lo stile funzionerà per l'output desiderato come t. Sono più preoccupato per la rientranza e la stampa delle newline di quanto non mi importi se usa uguali o due punti. – Krejko

+0

Sfortunatamente, non ho più il codice che ha prodotto il mio miglior tentativo ma consisteva in niente di diverso [myDescriptionString stringByReplacingOccurrencesOfString: @ "\\" withString: @ "\"] che rimuoveva tutti i caratteri di escape che erano stati aggiunti . Non riuscivo a capire come aggiungere correttamente nel rientro. – Krejko

risposta

5

Il seguente metodo potrebbe non essere il più elegante, ma sembra produrre il risultato desiderato:

@interface NSObject (MyPrettyPrint) 
- (NSString *)prettyPrint; 
@end 

// === ADDED CODE FOR CUSTOM OBJECTS (1) === 
@protocol ObjectToDictionary <NSObject> 
-(NSDictionary *)toDictionary; 
@end 
// === END OF ADDED CODE (1) === 

@implementation NSObject (MyPrettyPrint) 

- (NSString *)prettyPrint 
{ 
    BOOL isColl; 
    return [self prettyPrintAtLevel:0 isCollection:&isColl]; 
} 

- (NSString *)prettyPrintAtLevel:(int)level isCollection:(BOOL *)isCollection; 
{ 

// === ADDED CODE FOR CUSTOM OBJECTS (2) === 
    if ([self respondsToSelector:@selector(toDictionary)]) { 
     NSDictionary *dict = [(id <ObjectToDictionary>)self toDictionary]; 
     return [dict prettyPrintAtLevel:level isCollection:isCollection]; 
    } 
// === END OF ADDED CODE (2) === 

    NSString *padding = [@"" stringByPaddingToLength:level withString:@" " startingAtIndex:0]; 
    NSMutableString *desc = [NSMutableString string]; 

    if ([self isKindOfClass:[NSArray class]]) { 
     NSArray *array = (NSArray *)self; 
     NSUInteger cnt = [array count]; 
     [desc appendFormat:@"%@(\n", padding]; 
     for (id elem in array) { 
      BOOL isColl; 
      NSString *s = [elem prettyPrintAtLevel:(level+3) isCollection:&isColl]; 
      if (isColl) { 
       [desc appendFormat:@"%@", s]; 
      } else { 
       [desc appendFormat:@"%@ %@", padding, s]; 
      } 
      if (--cnt > 0) 
       [desc appendString:@","]; 
      [desc appendString:@"\n"]; 
     } 
     [desc appendFormat:@"%@)", padding ]; 
     *isCollection = YES; 

    } else if ([self isKindOfClass:[NSDictionary class]]) { 
     NSDictionary *dict = (NSDictionary *)self; 
     [desc appendFormat:@"%@{\n", padding]; 
     for (id key in dict) { 
      BOOL isColl; 
      id value = dict[key]; 
      NSString *s = [value prettyPrintAtLevel:(level+3) isCollection:&isColl]; 
      if (isColl) { 
       [desc appendFormat:@" %@%@ =\n%@\n", padding, key, s]; 
      } else { 
       [desc appendFormat:@" %@%@ = %@\n", padding, key, s]; 
      } 
     } 
     [desc appendFormat:@"%@}", padding ]; 
     *isCollection = YES; 

    } else { 
     [desc appendFormat:@"%@", self]; 
     *isCollection = NO; 
    } 

    return desc; 
} 

Esempio:

NSDictionary *dict = @{@"People": @[ 
    @{ 
     @"Name": @"Person 1", 
     @"Gender": @"Male", 
     @"Addresses": @[ 
      @{ 
       @"Address Name": @"Home Address", 
       @"Street": @"123 Street St.", 
       @"Zip": @12345 
      }, 
     ], 
     @"Cars": @[ 
      @{ 
       @"Make": @"Ford", 
       @"Model": @"NewFord", 
       @"Insured Drivers": @[ 
        @{@"Name": @"Person 1"}, 
        @{@"Name": @"Person 2"}, 
       ] 
      }, 
     ], 
    }, 

]}; 

NSLog(@"People =\n%@", [dict[@"People"] prettyPrint]); 

uscita:

 
People = 
(
    { 
     Name = Person 1 
     Gender = Male 
     Cars = 
     (
     { 
      Model = NewFord 
      Make = Ford 
      Insured Drivers = 
      (
       { 
        Name = Person 1 
       }, 
       { 
        Name = Person 2 
       } 
      ) 
     } 
    ) 
     Addresses = 
     (
     { 
      Zip = 12345 
      Address Name = Home Address 
      Street = 123 Street St. 
     } 
    ) 
    } 
) 
+0

Questo è il molto vicino alla soluzione che ho attualmente. Tuttavia, quando applicato al mio esempio con ogni oggetto che crea il valore del dizionario di se stesso come descrizione, ogni riga è al primo livello di indentazione. Questo mette l'output quasi identico alla risposta che ho elencato come il mio miglior tentativo. Grazie per la tua risposta, sento che ci stiamo avvicinando molto! – Krejko

+0

Ogni livello della gerarchia dell'oggetto ha bisogno di costruire una rappresentazione del dizionario di se stesso per la stampa. Altrimenti i dati analizzati dal mio JSON sono memorizzati in proprietà su questi oggetti. In questo formato, l'oggetto non è facilmente stampabile. Il mio tentativo di rendere questi oggetti facilmente stampabili includeva la memorizzazione nella cache di questi valori in un dizionario e la stampa del dizionario nella descrizione. Per favore fatemi sapere se siete a conoscenza di un modo migliore per farlo. – Krejko

+0

@Krejko: Non ho mai visto prima di avere oggetti personalizzati 'Car',' Address', ecc. Il mio metodo doveva essere applicato al dizionario completo che si ottiene da NSJSONSerialization. –