web-dev-qa-db-ja.com

NSJSONSerializationのエラー-JSON書き込みの無効なタイプ(メニュー)

非常によく似た属性を持つ3つのエンティティを持つコアデータを使用するアプリがあります。関係は次のとおりです。

支店->>メニュー->>カテゴリ->> FoodItem

各エンティティにはクラスが関連付けられています:例

enter image description here

sqliteデータベースのデータのJSON表現を生成しようとしています。

//gets a single menu record which has some categories and each of these have some food items
id obj = [NSArray arrayWithObject:[[DataStore singleton] getHomeMenu]]; 

NSError *err;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:&err];

NSLog(@"JSON = %@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);

しかし、JSONの代わりに、SIGABRTエラーが発生します。

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

それを修正する方法や、エンティティクラス(ブランチ、メニューなど)JSONシリアル化に互換性を持たせる方法はありますか?

50
Vaibhav Garg

これは、「Menu」クラスがJSONでシリアル化できないためです。基本的に、言語はオブジェクトがJSONでどのように表現されるべきかを知りません(どのフィールドを含めるか、他のオブジェクトへの参照をどのように表現するか...)

NSJSONSerialization Class Reference から

JSONに変換できるオブジェクトには、次のプロパティが必要です。

  • 最上位のオブジェクトはNSArrayまたはNSDictionaryです。
  • すべてのオブジェクトは、NSString、NSNumber、NSArray、NSDictionary、またはNSNullのインスタンスです。
  • すべての辞書キーはNSStringのインスタンスです。
  • 数値はNaNまたは無限ではありません。

これは、言語が辞書をシリアル化する方法を知っていることを意味します。したがって、メニューからJSON表現を取得する簡単な方法は、Menuインスタンスのディクショナリ表現を提供し、それをJSONにシリアル化することです。

- (NSDictionary *)dictionaryFromMenu:(Menu)menu {
    [NSDictionary dictionaryWithObjectsAndKeys:[menu.dateUpdated description],@"dateUpdated",
    menu.categoryId, @"categoryId",
    //... add all the Menu properties you want to include here
    nil];
}

そして、あなたはこのように使うことができます:

NSDictionary *menuDictionary = [self dictionaryFromMenu:[[DataStore singleton] getHomeMenu]]; 

NSError *err;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:menuDictionary options:NSJSONWritingPrettyPrinted error:&err];

NSLog(@"JSON = %@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
81
Julien

isValidJSONObjectには、オブジェクトをシリアル化できるかどうかを示すクラスメソッドNSJSONSerializationがあります。 Julienが指摘したように、おそらくオブジェクトをNSDictionaryに変換する必要があります。 NSManagedModelは、エンティティのすべての属性を取得するための便利なメソッドを提供します。したがって、NSManagedObjectに変換するメソッドを持つNSDictionaryのカテゴリを作成できます。この方法では、辞書に変換する各エンティティに対してtoDictionaryメソッドを記述する必要はありません。

@implementation NSManagedObject (JSON)

- (NSDictionary *)toDictionary
{
    NSArray *attributes = [[self.entity attributesByName] allKeys];
    NSDictionary *dict = [self dictionaryWithValuesForKeys:attributes];
    return dict;
}
24
Edward Huynh

NSJSONSerializationクラスの+ isValidJSONObject:メソッドを使用できます。有効でない場合は、NSStringの-initWithData:encoding:メソッドを使用できます。

- (NSString *)prettyPrintedJson:(id)jsonObject
{
    NSData *jsonData;

    if ([NSJSONSerialization isValidJSONObject:jsonObject]) {
        NSError *error;
        jsonData = [NSJSONSerialization dataWithJSONObject:jsonObject
                                                           options:NSJSONWritingPrettyPrinted
                                                             error:&error];

        if (error) {
            return nil;
        }
    } else {
        jsonData = jsonObject;
    }

    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
1
Fatih Aksu

キーを値で切り替えました:@ {value:@ "key"} @ {@ "key":value}である必要があります

0
jonypz