Разбор JSON-коллекции из Rails в Objective-C на iPhone - PullRequest
2 голосов
/ 26 января 2011

Я использую TouchJSON для анализа выходных данных JSON Rails API, но у меня возникли трудности.Общая цель состоит в том, чтобы перебрать ответ, проанализировать JSON, создать экземпляр Round для каждого объекта JSON и вставить эти Round объекты в NSArray, чтобы я мог загрузить его в UITableView.Поэтому, если есть более простой способ сделать это, чем то, что я собираюсь показать (что в настоящее время НЕ работает, кстати), пожалуйста, дайте мне знать.

Rails API возвращает коллекцию, которая выглядит кое-чтокак это:

[
  { 
    "round": { "course_title": "Title A", "result": "+8" }
  },
  { 
    "round": { "course_title": "Title B", "result": "+4" }
  },
  ...
]

Я также использую ASIHTTPRequest и могу успешно получить ответ, используя:

NSString *responseString = [request responseString];

Но оттуда я не могу никуда добраться.Вот более-менее то, что предлагает TouchJSON:

NSString *jsonString = [request responseString]; // [{"round":{...}}, ..., {"round:{...}}]
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSDictionary *dictionary = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:nil];

// then I do this...
NSLog(@"JSON: %@", dictionary); // JSON: null

Я подумал, что смогу пройтись по словарю и создать сопоставления объектов, используя мой класс Round.Но, возможно, это совершенно неправильный подход.

Я думаю, что JSON, возвращаемый из Rails, представляет собой массив объектов JSON, поэтому, возможно, именно поэтому анализатор JSON не распознает его как допустимый JSON?Отсюда у меня два вопроса:

1) Должен ли TouchJSON принимать массив объектов JSON, например, что возвращает мой API?

2) Можно ли привести responseString кNSArray, чтобы я мог проходить через каждый «раунд» и анализировать JSON таким образом?Если я удаляю первый и последний символы из строки ответа (то есть «[» и «]»), анализатор JSON будет захватывать только первый «раунд» в коллекции.

3) Я собираюсь сделать этовесь процесс правильно?

Любые советы / рекомендации будут высоко оценены.

Ответы [ 4 ]

21 голосов
/ 27 января 2011

TouchJSON представляет три основных способа перехода от JSON к объекту Obj-C. Все они присутствуют в заголовке для CJSONDeserializer, который вы уже используете:

- (id)deserialize:(NSData *)inData error:(NSError **)outError;

- (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError;
- (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError;

Первый из них вернет возвращаемое значение: словарь, массив, строку или любой другой корневой тип JSON.

Два других ожидают словарь или массив и будут жаловаться (то есть возвращать ноль и выдавать ошибку NSE), если они не получают правильные данные.

5 голосов
/ 27 января 2011

Метод deserializeAsDictionary:error: для CJSONDeserializer основан на методе scanJSONDictionary:error: для CJSONScanner. Этот метод ожидает, что «словарь» будет литералом объекта. Поэтому ваши данные должны начинаться с {. Поскольку ваши данные являются массивом, вы можете использовать метод deserializeAsArray:error: CJSONDeserializer.

4 голосов
/ 27 января 2011

Внимательно прочитайте документацию, ваш код неверен. Это должно выглядеть так:

NSData *jsonData = [request responseData]
NSArray *rounds = [[CJSONDeserializer deserializer] deserialize:jsonData error:nil];

// then I do this...
NSLog(@"JSON: %@", rounds);

Вы также могли бы использовать:

NSArray *rounds = [[CJSONDeserializer deserializer] deserializeAsArray:jsonData error:nil];

Однако ваша абсолютная САМАЯ БОЛЬШАЯ ошибка - ноль за ошибку. Вы могли бы избежать перехода к стеку на ВСЕХ, если бы передали что-то для NSError и затем проверили это.

1 голос
/ 27 января 2011

С правильными инструментами это НАСТОЛЬКО проще, чем вы делаете это. Я все время так делаю.

Используйте JS Framework Стига и импортируйте категорию NSString, предоставляющую метод JSONValue.

Тогда внутри вашего кода обработчика ответа ASIHTTPRequest, сделайте так:

NSMutableArray *roundlist = [NSMutableArray array];
NSArray *results = [[request responseString] JSONValue];
for (NSDictionary *item in results) {
    Round *myRound = [item objectForKey:@"round"];
    //don't actually do the above. Do whatever you do to instantiate a 'Round'.
    [roundlist addObject:myRound];
}
[self.tableView reloadData];

РЕДАКТИРОВАТЬ: Geezo. Возражение отмечено относительно valueForKey: vs objectForKey :. Я обновил свой пример кода, и я думаю, что мы все кое-что узнали здесь.

Я также не имел в виду оскорбление фразой «с правильными инструментами». OP хотел упростить свой код, и ПРАВИЛЬНЫЙ ИНСТРУМЕНТ для этого - библиотека с самым простым интерфейсом. Я не имею ничего против TouchJSON как такового, но JSON Framework имеет более простой интерфейс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...