嵌套的NSDictionary描述转义字符问题

时间:2013-04-16 16:52:13

标签: objective-c escaping nested nsdictionary

我正在尝试打印出一个客观化的JSON结构,我将其保存在层次结构中的多个词典中。我想通过NSObject的description方法执行此操作,以便每个嵌套字典的描述方法都被调用,同时返回其值。

期望的结果

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

但是,我遇到了一个问题,即每个嵌套字典的返回字符串都会为返回字符串传递的层次结构的每个级别转义一次。

实际结果

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 )

我已经读过这与描述添加这些转义字符的方式有关,因为它使用类似syslog实用程序的东西,但我相信我想要的功能是由于NSArray如何以类似的方式描述其内容我希望的方式。我已经尝试迭代结果字符串并解析出转义字符,但到目前为止,我提出的最好的结果是所有字典中所有属性的非分层列表。

最佳尝试

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

我想知道是否有其他人遇到过这个问题以及他们是如何克服这个问题的。

欢迎任何和所有建议。 谢谢你的期待。

更新1: 根据评论中的建议,我尝试使用以下NSDictionary类别方法将我的字典对象解析为JSON字符串以进行打印:

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

然后,在我的层次结构的每个级别,我在每个JSONDescription方法中调用我的字典对象description。但是,似乎没有调用嵌套对象的description方法。这导致以下异常:

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

示例实施

#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

1 个答案:

答案 0 :(得分:5)

以下方法可能不是最优雅的,但它似乎产生了所需的输出:

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

示例:

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

输出:

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