2013-04-16 24 views
6

Tôi đang cố gắng in ra một cấu trúc JSON đối tượng mà tôi đang lưu trong nhiều từ điển trong một hệ thống phân cấp. Tôi muốn thực hiện điều này thông qua phương thức description của NSObject sao cho mỗi phương thức mô tả của từ điển lồng nhau cũng được gọi là trả về giá trị của nó.Nested NSDictionary Description Escape Character Problems

mong muốn Kết quả

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

Tuy nhiên, tôi đã chạy vào một vấn đề mà các chuỗi lợi nhuận cho mỗi từ điển lồng nhau là nhận được thoát khỏi một lần cho mỗi cấp độ của hệ thống phân cấp các chuỗi lợi nhuận được đi qua.

Kết quả thực tế

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) 

Tôi đã đọc rằng đây đã làm với cách mô tả thêm các ký tự thoát do nó sử dụng một cái gì đó giống như một tiện ích syslog, tuy nhiên tôi tin rằng các chức năng mà tôi mong muốn là có sẵn do cách NSArray mô tả nội dung của nó theo cách tương tự như cách tôi muốn. Tôi đã cố gắng lặp qua chuỗi kết quả và phân tích cú pháp các ký tự thoát nhưng cho đến nay kết quả tốt nhất mà tôi đã đưa ra là danh sách không phân cấp của tất cả các thuộc tính trong tất cả các từ điển.

Cố gắng tốt nhất

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

Tôi đã tự hỏi nếu bất cứ ai khác đã đi qua vấn đề này và cách họ đã vượt qua nó.

Bất kỳ và tất cả đề xuất đều được chào đón. Cảm ơn bạn đã tìm kiếm.

UPDATE 1: Theo lời khuyên trong các ý kiến, tôi đã cố gắng phân tích đối tượng từ điển của tôi để chuỗi JSON để in bằng cách sử dụng phương pháp loại NSDictionary sau:

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

Sau đó, tại mỗi mức độ của tôi hệ thống phân cấp, tôi đang gọi đối tượng từ điển của tôi là JSONDescription trong mỗi phương thức description. Tuy nhiên, nó không xuất hiện mà phương thức description của đối tượng lồng nhau đang được gọi. Điều này gây ra những ngoại lệ sau đây:

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

Ví dụ thực hiện

#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

Tôi hơi bối rối vì đôi khi bạn thấy "key = giá trị" (như trong một cuốn từ điển) và đôi khi "quan trọng: giá trị" (như trong JSON) trong ví dụ của bạn.Bạn muốn cái nào trong đầu ra? - Và bạn có thể cho thấy mã của bạn đã tạo ra "nỗ lực tốt nhất" không? –

+0

Ah vâng. Cảm ơn. Tôi đã sửa ví dụ. Trong khi tất nhiên tôi muốn họ được nhất quán, hoặc là phong cách sẽ làm việc cho sản lượng mong muốn như t. Tôi quan tâm hơn đến việc thụt đầu dòng và in các dòng mới hơn là tôi quan tâm nếu nó sử dụng dấu bằng hoặc dấu hai chấm. – Krejko

+0

Thật không may, tôi không còn mã sản xuất nỗ lực tốt nhất của tôi nhưng nó không có gì khác hơn một vài [myDescriptionString stringByReplacingOccurrencesOfString: @ "\\" withString: @ "\"] đã xóa tất cả các ký tự thoát đã được thêm vào . Tôi không thể tìm ra cách để thêm đúng vào thụt đầu dòng. – Krejko

Trả lời

5

Phương pháp sau đây có thể không phải là thanh lịch nhất, nhưng có vẻ như để sản xuất các đầu ra mong muốn:

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

Ví dụ:

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

Output:

 
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

Đây là giải pháp rất gần với giải pháp hiện tại của tôi. Tuy nhiên, khi áp dụng cho ví dụ của tôi với mỗi đối tượng tạo giá trị từ điển của chính nó như là mô tả, mọi dòng đều ở mức thụt lề đầu tiên. Điều này đặt đầu ra gần giống với câu trả lời mà tôi đã liệt kê là nỗ lực tốt nhất của tôi. Cảm ơn bạn đã trả lời, tôi cảm thấy như chúng tôi đang tiến gần hơn! – Krejko

+0

Mỗi lớp của hệ thống phân cấp đối tượng cần xây dựng một biểu diễn từ điển của chính nó để in. Nếu không thì dữ liệu được phân tích cú pháp từ JSON của tôi được lưu trữ trong các thuộc tính trên các đối tượng này. Ở định dạng này, đối tượng không dễ in được. Nỗ lực của tôi để làm cho các đối tượng này dễ dàng in được bao gồm bộ nhớ đệm các giá trị này vào từ điển và in từ điển vào phần mô tả. Vui lòng cho tôi biết nếu bạn biết cách tốt hơn để thực hiện việc này. – Krejko

+0

@Krejko: Tôi không thấy trước đó bạn có các đối tượng tùy chỉnh 'Xe',' Địa chỉ', vv Phương pháp của tôi có nghĩa là được áp dụng cho từ điển hoàn chỉnh mà bạn nhận được từ NSJSONSerialization. –