2013-04-16 26 views
6

Próbuję wydrukować zobiektywizowaną strukturę JSON, którą zapisuję w wielu słownikach w hierarchii. Chciałbym to zrobić za pomocą metody NSObject description, aby każda metoda opisowa zagnieżdżonego słownika została wywołana, zwracając również jego wartość.Zagnieżdżone NSDictionary Opis Escape Character Problems

pożądanego rezultatu

 //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 

Jednakże I zostały uruchomione do problemu, że ciąg zwrotny dla każdego zagnieżdżonego słownika jest coraz uciekł raz dla każdego poziomu hierarchii, że ciąg zwrotny zostaje przekazana przez.

Rzeczywista Wynik

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) 

Czytałem, że ma to związek z tym, jak opis dodaje te znaki ewakuacyjne ze względu na jego użyciu coś jak syslog użyteczności, jednak wierzę, że funkcje, które pragnę jest dostępny ze względu na to, jak NSArray opisuje jego zawartość w podobny sposób, jak chciałbym. Próbowałem iterować ciąg wyniku i analizowanie znaków escape, ale jak dotąd najlepszym wynikiem, jaki wymyśliłem, jest niehierarchiczna lista wszystkich właściwości we wszystkich słownikach.

Najlepsza próba

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 
} 
) 
} 
) 
} 
) 

Zastanawiałem się, czy ktoś inny nie natknąć się ten problem i jak go pokonaliśmy.

Wszelkie sugestie są mile widziane. Dzięki za spojrzenie.

UPDATE 1: Zgodnie z radą w komentarzach, próbowałem parsowania Mój słownik obiektów do ciągów JSON do drukowania za pomocą następującego NSDictionary metodę kategorii:

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

Następnie na każdym poziomie mojego hierarchii, nazywam obiekt mojego obiektu słownikowego JSONDescription w każdej metodzie description. Jednak nie wygląda na to, że wywoływana jest metoda zagnieżdżonego obiektu description. To powoduje następujące wyjątki:

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

przykładów realizacji

#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

Jestem nieco zdezorientowany bo czasami pokazać „klucz = wartość” (jak w słowniku), a czasami „klucz: wartość” (jak w JSON) w swoich przykładach.Który chcesz na wyjściu? - Czy możesz pokazać swój kod, który wyprodukował "najlepszą próbę"? –

+0

Ah tak. Dzięki. Naprawiłem przykład. Chociaż oczywiście chciałbym, żeby były spójne, albo styl będzie działał dla pożądanej wydajności jako t. Bardziej niepokoję się wcięciem i drukowaniem znaków nowej linii, niżbym się obawiał, gdyby używał równań lub dwukropków. – Krejko

+0

Niestety, nie mam już kodu, który wyprodukował moją najlepszą próbę, ale składał się z zaledwie kilku różnych [myDescriptionString stringByReplacingOccurrencesOfString: @ "\\" withString: @ "\"], które usunęły wszystkie dodane znaki, które zostały dodane . Nie mogłem wymyślić, jak prawidłowo dodać z powrotem wcięcia. – Krejko

Odpowiedz

5

Poniższa metoda może nie być najbardziej eleganckie, ale wydaje się, aby uzyskać żądany wynik:

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

Przykład:

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

wyjściowa:

 
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

Jest to bardzo zbliżone do rozwiązania, które mam obecnie. Jednak po zastosowaniu do mojego przykładu z każdym obiektem tworzącym wartość słownika jako opisem, każda linia jest na pierwszym poziomie wcięcia. Stawia to wynik prawie identyczny z odpowiedzią, którą wymieniłem jako moją najlepszą próbę. Dziękuję za odpowiedź, czuję, że zbliżamy się coraz bardziej! – Krejko

+0

Każda warstwa hierarchii obiektów musi skonstruować słownikową reprezentację w celu drukowania. W przeciwnym razie dane analizowane z mojego JSON są przechowywane we właściwościach tych obiektów. W tym formacie obiekt nie jest łatwy do wydrukowania. Moja próba łatwego drukowania tych obiektów obejmowała zapisanie tych wartości do słownika i wydrukowanie słownika do opisu. Daj mi znać, jeśli wiesz o tym lepszy sposób. – Krejko

+0

@Krejko: Nie widziałem wcześniej, że masz niestandardowe obiekty 'Car',' Address' itd. Moja metoda miała być zastosowana do kompletnego słownika, który otrzymujesz od NSJSONSerialization. –