NSURLConnection против NSData + GCD - PullRequest
       17

NSURLConnection против NSData + GCD

29 голосов
/ 14 сентября 2011

NSData всегда имел очень удобный метод, называемый +dataWithContentsOfURL:options:error:. Несмотря на удобство, он также блокирует выполнение текущего потока, что означало, что он практически бесполезен для производственного кода (Игнорирование NSOperation). Я использовал этот метод так редко, что совершенно забыл, что он существует. До недавнего времени.

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

Скажем, мой типичный класс загрузчиков работает где-то в пределах 100 строк. Это 100 строк для асинхронного выполнения, что NSData может делать синхронно в одной строке. Для большей сложности этому классу загрузчика необходим собственный протокол делегата, чтобы сообщить о завершении и ошибках своему владельцу, а владельцу необходимо каким-то образом реализовать этот протокол.

Теперь введите Grand Central Dispatch, и я могу сделать что-то столь же фантастически простое, как:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

    NSData* data = [NSData dataWithContentsOfURL:someURL];
    // Process data, also async...

    dispatch_async(dispatch_get_main_queue(), ^(void) {
        // Back to the main thread for UI updates, etc.
    });
});

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

Таким образом, мой вопрос: есть ли какие-либо предостережения относительно использования NSData + GCD для простых задач загрузки данных вместо NSURLConnection (при условии, что меня не волнуют такие вещи, как процесс загрузки)?

Ответы [ 3 ]

22 голосов
/ 14 сентября 2011

Вы теряете много функциональности здесь:

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

, и, вероятно, есть еще кое-что.


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

См., например, мой собственный класс OHURLLoader, который прост, и я сделал API простым в использовании с блоками:

NSURL* url = ...
NSURLRequest* req = [NSURLRequest requestWithURL:url];

OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) {
    NSLog(@"Download of %@ done (statusCode:%d)",url,httpStatusCode);
    if (httpStatusCode == 200) {
        NSLog(%@"Received string: %@", loader.receivedString); // receivedString is a commodity getter that interpret receivedData using the TextEncoding specified in the HTTP response
    } else {
        NSLog(@"HTTP Status code: %d",httpStatusCode); // Log unexpected status code
    }
} errorHandler:^(NSError *error) {
    NSLog(@"Error while downloading %@: %@",url,error);
}];

См. Файл README и пример проекта на github для получения дополнительной информации.

Таким образом:

  • вы все еще полагаетесь на асинхронныйметоды, предоставляемые NSURLConnection (и какв документации Apple говорится о параллельном программировании , если API уже существует для выполнения асинхронных задач, используйте его вместо использования другой технологии потоков, если это возможно)
  • вы сохраняете преимущества NSURLConnection (обработка ошибок,и т.д.)
  • но у вас также есть преимущества синтаксиса блоков, которые делают ваш код более читабельным, чем при использовании методов делегата
12 голосов
/ 15 сентября 2011

Видео сессий WWDC 2010 :

  • WWDC 2010, сессия 207 - Сетевые приложения для iPhone OS, часть 1
  • WWDC 2010, сессия 208 - Сетевые приложения для iPhone OS, часть 2

Лектор сказал

«Нити злые ™».

Для сетевого программирования настоятельно рекомендуется использовать асинхронный API с RunLoop.

Потому что, если вы используете NSData + GCD, как показано ниже, он использует один поток на соединение.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    NSData* data = [NSData dataWithContentsOfURL:someURL];

И он может использовать много соединений и много потоков. Слишком легко использовать GCD :-) Затем многие потоки съедают огромное количество памяти для своего стека. Таким образом, вам лучше использовать асинхронный API, как сказал AliSoftware.

2 голосов
/ 16 ноября 2014

Начиная с OS X v10.9 и iOS 7 предпочтительным способом является использование NSURLSession . Он предоставляет вам приятный блочный интерфейс и такие функции, как отмена, приостановка и фоновая загрузка.

...