Разработка Показываем таймлайн Twitter

Никита Narmo Дёнин avatar | 13
FavoriteLoading В закладки

В связи с большой популярностью различных социальных сетей и микроблогов перед разработчиками приложений для iPhone часто возникает задача интеграции с ними. В этой статье будет показано, как простыми средствами встроить в приложение ленту последних записей из Твиттера.

Задача получения ленты записей из Твиттера делится на загрузку данных с сервера, их обработку и отображение. В качестве источника записей использовался формат JSON. Я продемонстрирую работу с JSON на примере одной из существующих библиотек, а также способы получения данных с удалённых серверов с помощью синхронных и асинхронных запросов.

Существует несколько свободных библиотек для работы с JSON на устройствах под управлением iOS. Из самых известных стоит отметить JSON Framework (именно эта библиотека была использована мной в процессе написания статьи) и TouchJSON. Эти библиотеки готовы для использования в проектах для iOS. Можно также воспользоваться другими библиотеками (например, легковесной cJSON), написав для них «обёртки» на Objective-C (такие обёртки по-английски называются wrapper).

Для получения последних записей из Твиттера не обязательно регистрировать своё приложение и получать ключ разработчика. У Твиттера есть открытый API, позволяющий получить ленту в виде объектов JSON. Для её получения надо всего лишь обратиться по адресу следующего вида:

http://twitter.com/statuses/user_timeline/USERNAME.json

где USERNAME — это имя пользователя, зарегистрированного в Твиттере. В случае, если такого пользователя не существует, придёт ответ в виде JSON, содержащий описание ошибки.

Синхронная загрузка данных

При использовании синхронных запросов мы отправляем запрос на сервер и ждём, пока от него придёт ответ. При этом выполнение потока, из которого была осуществлена отправка запроса, приостанавливается до прихода ответа. После того, как сервер ответил, и мы получили необходимые для работы данные, выполнение потока продолжается.

Примечание: для большей наглядности я постарался избежать autorelease-объектов там, где это возможно.

Синхронный запрос для получения ленты пользователя Твиттера отправляется следующим образом:

NSString *tweetsUrlString = [[NSString alloc] initWithFormat:@"http://twitter.com/statuses/user_timeline/%@.json", USERNAME];
NSURL *url = [[NSURL alloc] initWithString:tweetsUrlString];
[tweetsUrlString release];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[url release];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

В результате выполнения этого метода в объект responseData запишется ответ от сервера. Объекты response (экземпляр NSURLResponse) и error (экземпляр NSError) будут содержать соответственно данные ответа (например, кодировку возвращаемых данных или тип MIME) и ошибку, если таковая возникла в процессе выполнения запроса.

После получения необходимых данных в виде объекта NSData можно отправить их на разбор в парсер JSON. Как уже было сказано в начале статьи, я воспользовался библиотекой JSON Framework. Данные, полученные от сервера, были преобразованы в NSString, потому что парсер при разборе строки может возвращать также описание ошибки, если она возникнет.

NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSError *jsonError;
tweets = [[parser objectWithString:responseString error:&jsonError] retain];
[responseString release];

В результате выполнения этого кода в объекте tweets будет находиться массив из словарей (экземпляров NSDictionary), каждый из которых представляет одну запись в Twitter со всеми сопутствующими параметрами (такими, как текст твита, дата публикации, данные геолокации и т.п.). Этот массив можно обработать и вывести на экран. В демо-проекте к этой статье лента записей выводится в виде таблицы.

Асинхронная загрузка данных

Такой способ загрузки является более предпочтительным, так как процесс получения данных от удалённого сервера происходит в отдельном потоке и даёт больше возможностей для контроля за этим процессом. Создание соединения для асинхронного запроса происходит так:

NSString *tweetsUrlString = [[NSString alloc] initWithFormat:@"http://twitter.com/statuses/user_timeline/%@.json", USERNAME];
NSURL *url = [[NSURL alloc] initWithString:tweetsUrlString];
[tweetsUrlString release];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[url release];

mConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];

Параметр startImmediately:YES сообщает соединению, что загрузку можно начинать немедленно. Если передать в него значение NO, то отправку запроса придётся делать вручную:

mConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[mConnection start];

Объект-делегат, переданный в параметре delegate, содержит следующие методы, которые будут вызываться в процессе работы соединения.

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

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

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

Этот метод вызывается после установления соединения. Из объекта response можно получить различные данные об ответе от сервера. Например, значение свойства expectedContentLength можно использовать для отрисовки прогресса загрузки.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

Асинхронные запросы получают данные порциями, и при получении очередной порции будет вызываться этот метод. Поэтому перед запуском запроса необходимо создать экземпляр объекта NSMutableData, в который и будут дописываться полученные порции данных.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection

Этот метод вызывается по завершении загрузки данных. Здесь можно обработать полученные данные, освободить ненужные объекты и передать управление объекту, который ожидает эти самые данные (в нашем случае это таблица, куда выводятся твиты).

В демонстрационном проекте к этой статье на экран выводятся твиты из ленты Артура Малосиева:


В проекте используется макрос TRACE для переопределения NSLog. Сделано это с целью отключения вывода отладочной информации при сборке цели Release. Макрос выглядит так:

#ifdef DEBUG
#define TRACE(a, ...) NSLog(a, ##__VA_ARGS__)
#else
#define TRACE(a, ...)
#endif

Для того, чтобы этот макрос заработал, и вывод NSLog отключался при сборке цели Release, необходимо в настройках проекта сделать следующее.
— переходим на вкладку Build
— в выпадающем списке Configuration выбираем Debug
— в строке поиска вводим текст cflags
— в пункте Other C Flags вводим следующий параметр: -DDEBUG

Этот параметр сообщит компилятору, что при сборке цели Debug будет определена переменная DEBUG, и все вхождения TRACE будут заменены на NSLog. При сборке цели Release все вхождения TRACE будут отброшены, и вывод отладочной информации производиться не будет.


Исходные коды библиотеки JSON Framework распространяются на условиях лицензии BSD и доступны на github.

Скачать исходные коды демонстрационного проекта к статье можно также скачать с github. Проект распространяется на условиях Public Domain, и любая его часть может быть использована в любых целях без указания моего авторства.

1 Звезд2 Звезды3 Звезды4 Звезды5 Звезд (Проголосуйте первым за статью!)
undefined
iPhones.ru
В связи с большой популярностью различных социальных сетей и микроблогов перед разработчиками приложений для iPhone часто возникает задача интеграции с ними. В этой статье будет показано, как простыми средствами встроить в приложение ленту последних записей из Твиттера. Задача получения ленты записей из Твиттера делится на загрузку данных с сервера, их обработку и отображение. В качестве...
Прокомментировать

🙈 Комментарии 13

  1. TauruS_iPhone4_now avatar
    TauruS_iPhone4_now15 апреля 2011
    0

    Сам разработкой пока не занимаюсь, но появление подобных статей создает практически отдельный раздел сайта. Так держать! Думаю в будущем Никита сделает многое для айфонсру)

    iLokki avatar
    iLokki16 апреля 2011
    0

    @TauruS_iPhone4_now, +1
    Отличная статья, полностью поддерживаю идею отдельного раздела.
    Никита, спасибо!

  2. Novikoff avatar
    Novikoff15 апреля 2011
    0

    ув.разработчики загляните сюда http://www.iphones.ru/forum/index.php?showtopic=77833
    нужна помощь

  3. Rusik avatar
    Rusik16 апреля 2011
    0

    Никита, вижу ты уже бывалый разработчик.
    А под мак писать умеешь?
    у меня вот вопрос один
    http://*****
    Запрещено давать ссылки на сторонние ресурсы. Кроме того, есть раздел разработчиков на форуме.

    никто не отвечает пока
    может ты знаешь)

    Rusik avatar
    Rusik16 апреля 2011
    0

    @Rusik, пипец вы злые какие

    ну в жопу ваш форум
    он нифига неудобный

    Никита Narmo Дёнин avatar
    Никита Narmo Дёнин16 апреля 2011
    0

    @Rusik, Под Мак писать не умею.

    Afx40 avatar
    Afx4016 апреля 2011
    0

    @Rusik, а тут никакой Голубиной книги с тайными знаниями не надо, все по уставу и инструкции в три строчки.

    В windowDidLoad добавляем:

    // получаем root-control
    NSView* root = [[[self window] contentView] superview];
    // определяем его размер
    NSRect rc = [root bounds];
    // кнопку размером 10х10 помещаем в заголовок с коорд 30,0
    // а что бы было красиво, выясняйте размер заголовка
    rc.origin.x += 30; rc.size.width = 10;
    rc.origin.y = rc.size.height – 10; rc.size.height = 10;
    // создаем кнопку
    NSButton butt = [[NSButton alloc] initWithFrame:rc];
    // добавляем ее в root-control
    [root addSubview:butt];
    // обработку событий добавляем к кнопке с помощью
    // setTarget и setAction

    Afx40 avatar
    Afx4016 апреля 2011
    0

    Извиняюсь, это ответ Novikoff-у, а не Rusik

  4. Rusik avatar
    Rusik16 апреля 2011
    0

    Помогите мне тоже кто нибудь
    вот вопрос
    http://www.iphones.ru/forum/index.php?showtopic=77843

  5. Afx40 avatar
    Afx4016 апреля 2011
    0

    Вы лучше здесь сформулируйте вопрос, а то там по ссылке надо регистрироваться, и письмо с регистрацией не высылается. Но сам по себе вопрос “Как работает NSUndoManager” очень странный – в документации вообще-то все есть.

    Rusik avatar
    Rusik16 апреля 2011
    0

    @Afx40, эт блин
    я думал вопросы всем без регистрации показываются

    ну вот собственно вопрос (там подсветка синтаксиса, все как надо)
    http://pastie.org/1800936

    Модераторам:
    Только вот не надо эту ссылку стирать и говорить, что это ссылка на сторонний ресурс. Там текст только

    Afx40 avatar
    Afx4016 апреля 2011
    0

    @Rusik, можете уже начинать нервно смеяться – у Вас ВСЕ ПРАВИЛЬНО. Не найдя ошибки, я специально проверил – создал doc-based app, дословно перенес туда Ваш код. Все превосходно работает (Xcode 3.2.5). Могу высказать только одно предположение – пока Вы экспериментировали, что-то сломали в другом месте. Попробуйте создать проект заново.

    Afx40 avatar
    Afx4016 апреля 2011
    0

    P.S. Кстати, Вы там ничего не удаляли из сгенерированного текста, я надеюсь, а только добавляли свой текст?

Вы должны авторизоваться или зарегистрироваться для комментирования.

Нашли орфографическую ошибку в новости?

Выделите ее мышью и нажмите Ctrl+Enter.

Как установить аватар в комментариях?

Ответ вот здесь