6

階層内の複数の辞書に保存しているオブジェクト化された JSON 構造を出力しようとしています。descriptionネストされた各辞書の説明メソッドが呼び出され、その値も返されるように、NSObjectのメソッドを介してこれを行いたいと思います。

望ましい結果

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

ただし、ネストされた各辞書の戻り文字列が、戻り文字列が渡される階層のレベルごとに 1 回エスケープされるという問題が発生しています。

実結果

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 ユーティリティのようなものを使用しているため、description がこれらのエスケープ文字を追加する方法に関係していることを読みましたが、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;
}

次に、階層の各レベルで、JSONDescriptiondescriptionメソッドで辞書オブジェクトを呼び出しています。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
4

1 に答える 1

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

出力:

人々 =
(
   {
      名前 = 個人 1
      性別=男性
      車 =
      (
         {
            モデル=ニューフォード
            メーカー=フォード
            被保険者ドライバー =
            (
               {
                  名前 = 個人 1
               }、
               {
                  名前 = 人 2
               }
            )
         }
      )
      住所 =
      (
         {
            郵便番号 = 12345
            住所名 = 自宅住所
            ストリート = 123 ストリート ストリート
         }
      )
   }
)
于 2013-04-16T19:30:24.267 に答える