Отправка GET запроса (NSURLConnection, iOS, Xcode 4.2)

Уроки по созданию приложений для iOS (iPhone, iPad, iPod Touch) в Xcode (Objective-C)
Ответить
Аватара пользователя
Александр
Создатель сайта
Создатель сайта
Сообщения: 4574
Зарегистрирован: 27 сен 2009, 16:45

Отправка GET запроса (NSURLConnection, iOS, Xcode 4.2)

Сообщение Александр »

Отправка GET запроса (NSURLConnection, iOS, Xcode 4.2)
Objective-C 2.0, iPhone, iPod, iPad, iOS

Для того чтобы понять что описывается в этой статье, вам нужно иметь представление о том как создаются приложения для iOS. Если вы еще не понимаете основ Objective-C, то сначала посмотрите тему Разработка приложений для iOS. С чего начать (Xcode 4.2).


Теория

Для выполнения GET запросов в Objective-C можно использовать NSURLConnection.
Подробную информацию о NSURLConnection можно почитать в официальной документации https://developer.apple.com/library/mac ... rence.html
и
https://developer.apple.com/library/mac ... ction.html

NSURLConnection поддерживает синхронное и асинхронное выполнение запросов.

Для выполнения синхронных запросов используется sendSynchronousRequest:returningResponse:error:
Использование такого запроса не рекомендуется. Работа приложения остановится, пока данные не будут получены полностью, не произойдёт ошибка или истечет тайм-аут соединения. При использовании синхронного запроса есть и другие ограничения.


Для асинхронных запросов используется initWithRequest:delegate:

Код: Выделить всё

- (id)initWithRequest:(NSURLRequest *)request delegate:(id < NSURLConnectionDelegate >)delegate
или initWithRequest:delegate:startImmediately:

- request
URL запрос

- delegate
Делегат получает сообщения в процессе загрузки данных.




В этой статье будет приведен пример использования асинхронного запроса.


Чтобы получить содержимое с URL адреса, необходимо реализовать следующие методы:

- connection:didReceiveResponse:
- connection:didReceiveData:
- connection:didFailWithError:
- connectionDidFinishLoading:



Создание приложения в Xcode 4.2 (без ARC)

1. Создаём новый проект
Называем его, например, MethodGET.
Добавляем Label, называем его label.


2. Пишем код
В ViewController.h объявляем переменную receivedData

Код: Выделить всё

#import <UIKit/UIKit.h> @interface ViewController : UIViewController {    IBOutlet UILabel *label;    NSMutableData *receivedData;} @end
Подробнее о NSMutableData можно прочитать здесь https://developer.apple.com/library/mac ... eData.html


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

Код: Выделить всё

- (void)viewDidLoad{    [super viewDidLoad];        // создаем запрос    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://flapps.ru/example/user-info.php"]                             cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];        // создаём соединение и начинаем загрузку    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];     if (connection) {        // соединение началось        label.text = @"Connecting...";        // создаем NSMutableData, чтобы сохранить полученные данные        receivedData = [[NSMutableData data] retain];    } else {        // при попытке соединиться произошла ошибка        label.text = @"Connection error!";    }                             }
- cachePolicy - политика кеширования
- timeoutInterval - ожидание запроса в секундах

Подробнее о NSURLRequest можно прочитать в документации
https://developer.apple.com/library/mac ... rence.html

Для того чтобы передать параметры в запросе, достаточно написать их в url строке, например

Код: Выделить всё

"http://flapps.ru/example/user-info.php?param1=1&param2=2"
Загрузка начинается сразу после получения сообщения initWithRequest:delegate:. Она может быть отменена в любое время, до того как делегат не получит сообщение connectionDidFinishLoading: или connection:didFailWithError:. Для отмены загрузки нужно отправить соединению сообщение cancel.


Когда сервер подготовит ответ, делегат получит сообщение connection:didReceiveResponse:. По ответу можно будет определить объем получаемых данных, MIME тип, имя файла и другие META данные.

Сообщение connection:didReceiveResponse: может быть получено несколько раз за одно соединение. Это может произойти в случае если сервер произведет переадресацию или в случае получения нескольких частей одного файла большого объема.
При каждом получении сообщения connection:didReceiveResponse: нужно очистить все ранее полученные данные.

Код: Выделить всё

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{    // получен ответ от сервера    [receivedData setLength:0];}

Когда данные получаюся, посылается сообщение connection:didReceiveData:.
Данные могут быть получены не целиком, а по частям, поэтому все полученные данные надо объединять.
В этом методе можно сделать индикатор процесса загрузки файла.

Код: Выделить всё

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{    // добавляем новые данные к receivedData    [receivedData appendData:data];}

Если во время загрузки произойдёт ошибка, то делегат получит сообщение connection:didFailWithError:.
Сведения об ошибки будут переданы в объекте NSError.
Данные об ошибки также можно получить из userInfo dictionary, по ключу NSURLErrorFailingURLStringErrorKey.
Подробнее о NSError можно прочитать здесь https://developer.apple.com/library/mac ... rence.html

Код: Выделить всё

- (void)connection:(NSURLConnection *)connection  didFailWithError:(NSError *)error {    // освобождаем соединение и полученные данные    [connection release];    [receivedData release];        // выводим сообщение об ошибке    NSString *errorString = [[NSString alloc] initWithFormat:@"Connection failed! Error - %@ %@ %@",                             [error localizedDescription],                             [error description],                             [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]];    label.text = errorString;        [errorString release];}
localizedDescription, description, NSURLErrorFailingURLStringErrorKey - получаем описание ошибки.


Если соединение успешно завершено, то делигат получит сообщение connectionDidFinishLoading:.

Код: Выделить всё

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {    // данные получены    // здесь можно произвести операции с данными        // можно узнать размер загруженных данных    //NSString *dataString = [[NSString alloc] initWithFormat:@"Received %d bytes of data",[receivedData length]];        // если ожидаемые полученные данные - это строка, то можно вывести её    NSString *dataString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];        label.text = dataString;        // освобождаем соединение и полученные данные    [connection release];    [receivedData release];    [dataString release];}


Код полностью

Код: Выделить всё

- (void)viewDidLoad{    [super viewDidLoad];        // создаем запрос    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://flapps.ru/example/user-info.php"]                             cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];        // создаём соединение и начинаем загрузку    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];     if (connection) {        // соединение началось        label.text = @"Connecting...";        // создаем NSMutableData, чтобы сохранить полученные данные        receivedData = [[NSMutableData data] retain];    } else {        // при попытке соединиться произошла ошибка        label.text = @"Connection error!";    }                             } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{    // получен ответ от сервера    [receivedData setLength:0];} - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{    // добавляем новые данные к receivedData    [receivedData appendData:data];} - (void)connection:(NSURLConnection *)connection  didFailWithError:(NSError *)error {    // освобождаем соединение и полученные данные    [connection release];    [receivedData release];        // выводим сообщение об ошибке    NSString *errorString = [[NSString alloc] initWithFormat:@"Connection failed! Error - %@ %@ %@",                             [error localizedDescription],                             [error description],                             [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]];    label.text = errorString;        [errorString release];}  - (void)connectionDidFinishLoading:(NSURLConnection *)connection {    // данные получены    // здесь можно произвести операции с данными        // можно узнать размер загруженных данных    //NSString *dataString = [[NSString alloc] initWithFormat:@"Received %d bytes of data",[receivedData length]];        // если ожидаемые полученные данные - это строка, то можно вывести её    NSString *dataString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];        label.text = dataString;        // освобождаем соединение и полученные данные    [connection release];    [receivedData release];    [dataString release];}

3. Можно протестировать приложение
Можно запустить приложение в симуляторе или на своем устройстве.
О том как запустить приложение на своём устройстве без сертификата разработчика можно прочитать в теме Запуск приложения на iPhone без сертификата (Xcode 4.2).

Скрипт который я открывал в приложении показывает UserAgent.
При запуске приложения, я увидел html код загруженной страницы.

Код: Выделить всё

HTTP_USER_AGENT: MethodGET/1.0 CFNetwork/548.0.3 Darwin/11.2.0<br />
raeen
Сообщения: 4
Зарегистрирован: 05 май 2012, 00:17

Re: Отправка GET запроса (NSURLConnection, iOS, Xcode 4.2)

Сообщение raeen »

У меня после копирования данного куска куда в икскод, вылезло 13 ошибок
'release' is unavailable: not available in automatic reference counting mode
ARC forbids explicit message send of 'release'
'retain'...

как можно исправить ошибки?
Аватара пользователя
Александр
Создатель сайта
Создатель сайта
Сообщения: 4574
Зарегистрирован: 27 сен 2009, 16:45

Re: Отправка GET запроса (NSURLConnection, iOS, Xcode 4.2)

Сообщение Александр »

raeen
Не используй ARC. При создании нового проекта сними галку с "Use Automatic Reference Counting".
А если всё таки хочешь использовать ARC, тогда удали из кода все строки с release.
raeen
Сообщения: 4
Зарегистрирован: 05 май 2012, 00:17

Re: Отправка GET запроса (NSURLConnection, iOS, Xcode 4.2)

Сообщение raeen »

Александр писал(а): Не используй ARC. При создании нового проекта сними галку с "Use Automatic Reference Counting".
А если всё таки хочешь использовать ARC, тогда удали из кода все строки с release.
Большое спасибо! Отключил, ошибок больше нету.
А как проследить за процессом соединения? А то я запускаю приложение и просто белое окно.
И как получить ответное сообщение с сервера, после того, как я послал на него запрос?
Аватара пользователя
Александр
Создатель сайта
Создатель сайта
Сообщения: 4574
Зарегистрирован: 27 сен 2009, 16:45

Re: Отправка GET запроса (NSURLConnection, iOS, Xcode 4.2)

Сообщение Александр »

raeen писал(а):А как проследить за процессом соединения?
Александр писал(а):Когда данные получаюся, посылается сообщение connection:didReceiveData:.
Данные могут быть получены не целиком, а по частям, поэтому все полученные данные надо объединять.
В этом методе можно сделать индикатор процесса загрузки файла.
raeen писал(а):И как получить ответное сообщение с сервера
Александр писал(а):Если соединение успешно завершено, то делигат получит сообщение connectionDidFinishLoading:.
Описанного в этой статье не достаточно?
Ответить