Ошибка с NSJSONSerialization - Недопустимый тип записи JSON (меню)
У меня есть приложение, использующее основные данные с 3 объектами с очень похожими атрибутами. Связь такова:
Отрасль → > Меню → > Категория → > FoodItem
Каждый объект имеет ассоциированный класс: example
![enter image description here]()
Я пытаюсь создать JSON-представление данных в базе данных sqlite.
//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)'
Любые идеи, как это исправить или как сделать классы сущностей (Branch, Menu и т.д.) совместимыми с JSON-сериализацией?
Ответы
Ответ 1
Это потому, что ваш класс "Меню" не сериализуется в JSON. Bascially язык не знает, как ваш объект должен быть представлен в JSON (какие поля включать, как представлять ссылки на другие объекты...)
Из Справка класса NSJSONSerialization
Объект, который может быть преобразован в JSON, должен иметь следующее Свойства:
- Объект верхнего уровня - NSArray или NSDictionary.
- Все объекты являются экземплярами NSString, NSNumber, NSArray, NSDictionary или NSNull.
- Все словарные ключи являются экземплярами NSString.
- Числа не NaN или бесконечность.
Это означает, что язык знает, как сериализовать словари. Таким образом, простой способ получить представление JSON из вашего меню - предоставить представление в виде словаря ваших экземпляров меню, которое затем будет сериализоваться в 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]);
Ответ 2
Существует метод класса isValidJSONObject
на NSJSONSerialization
, который сообщает вам, может ли объект быть сериализован. Как указал Жюльен, вам, вероятно, придется преобразовать свой объект в NSDictionary
. NSManagedModel
предоставляет некоторые удобные методы для получения всех ваших атрибутов для вашего объекта. Таким образом, вы можете создать категорию для NSManagedObject
, у которой есть способ ее преобразования в NSDictionary
. Таким образом, вам не нужно писать метод toDictionary
для каждого объекта, который вы хотите преобразовать в словарь.
@implementation NSManagedObject (JSON)
- (NSDictionary *)toDictionary
{
NSArray *attributes = [[self.entity attributesByName] allKeys];
NSDictionary *dict = [self dictionaryWithValuesForKeys:attributes];
return dict;
}
Ответ 3
Вы можете использовать + isValidJSONObject: метод класса NSJSONSerialization. Если это недопустимо, вы можете использовать - initWithData: encoding: метод NSString.
- (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];
}
Ответ 4
У меня был ключ, переключенный со значением: @{значение: @ "key" }
Это должно быть @{@ "ключ": значение}