Ещё один пост, чтобы у самого в голове улеглось. Про работу с JSON в Objective-C на примере парсинга твитов из публичной ленты Twitter.
В Objective-C из коробки нет ничего для того, чтобы работать с данными в формате JSON. Есть только для работы с XML. Но есть фреймворк для работы с JSON, в случае если вас к этому вынуждает необходимость/прихоть/нежелание начальника отдавать данные в XML (нужное подчеркнуть). Его можно скачать на GitHub. На данный момент последняя версия 3.0.3. Есть ещё альфа 3.1, но это альфа.
Архив содержит в себе Readme, примеры, сам фреймворк и ещё какие-то файлы, предназначение которых мне пока неизвестно :)
Собственно сами файлы фреймворка находятся в папке Classes, которую и нужно перетащить в список файлов нашего проекта в XCode. Для удобства я переименовал после импорта папку в JSON.
В RootViewController.h мы импортируем фреймворк строкой:
#import "SBJson.h"
В RootViewController.h добавим такой код:
@interface RootViewController : UITableViewController {
NSMutableData *jsonData;
}
@property (nonatomic, retain) NSMutableData *jsonData;
@end
Мы объявляем свойство класса jsonData типа NSMutableData, в него мы будем складировать данные, которые нам вернёт запрос к API Twitter.
Строка property здесь нужна на случай, если мы хотим получить доступ к свойству jsonData вне нашего класса. nonatomic означает, что jsonData у нас не лочится (lock), то есть мы можем и получить, и изменить значение. Пишут, что nonatomic - работает быстрее, чем atomic. Atomic означает, что мы лочим значение. Насчет retain пишут: How the setter method will set the variable. Пока не понял, зачем это и как с этим работать, но без этой строки ничего не работает =).
Брать данные в JSON мы будет у Twitter'а. Благо у них для публичной ленты не нужно никаких авторизаций и токенов, достаточно послать запрос на определенный URL, для обкатки самое то.
Для начала - у нас есть класс RootViewController. В RootViewController.m разместим в viewDidLoad такой код:
@synthesize jsonData;
- (void)viewDidLoad {
[super viewDidLoad];
// создаем объект NSURL с адресом, на который будет идти запрос
NSURL *url = [ NSURL URLWithString: @"http://twitter.com/statuses/public_timeline.json" ];
// создаем объект NSURLRequest - запрос
NSURLRequest *theRequest=[NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// запускаем соединение
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
self.jsonData = [NSMutableData data];
} else {
NSLog(@"Connection failed");
}
[theConnection release];
}
Для обработки соединения и данных нужно добавить ещё такой код:
/**
* При получении новой порции данных добавляем их к уже полученным
**/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[jsonData appendData:data];
}
/**
* Если соединение не удалось - выводим в консоль сообщение об ошибке
**/
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"%@", error);
}
/**
* Когда все данные получены - разбираем их
**/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// сохраняем полученные данные в строку result
NSString *result = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// можно вывести в консоль и посмотреть - что мы получили
NSLog( @"%@",result );
// создаем объект с JSON-парсером
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
// Парсим строку данных result в объект класса NSArray (массив)
NSArray *dataObject = [jsonParser objectWithString:result error:nil];
// тут можно поставить Breakpoint
// не забываем убить объекты
[jsonParser release];
[result release];
}
Если поставить Breakpoint ( CMD + \) в указанном выше месте ( см. "тут можно поставить Breakpoint" ), то можно посмотреть значения на этом этапе выполнения кода. Из скрина ниже видно, что полученная нами строка из Twitter распарсилась в объект dataObject типа NSArray, который внутри себя содержит 20 элементов, то есть данные о 20 твитах публичной ленты.
После строки, где стоит Breakpoint, полученные данные уже можно как-то обрабатывать. Например, вывести в консоль полученные твиты в виде "Username - TweetText"
for ( NSDictionary *tweet in dataObject ) {
NSLog(@"%@ - %@", [[tweet objectForKey:@"user"] objectForKey:@"screen_name"], [tweet objectForKey:@"text"] );
}
Надеюсь, нигде не наврал и не ошибся. Поправкам/уточнениям только рад.