Подтвердить что ты не робот

NSURLConnection против NSData + GCD

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.
    });
});

И я могу бросить эту присоску в любом месте, где хочу, прямо в строке. Нет необходимости в классе загрузки, нет необходимости обрабатывать методы делегирования соединений. Легкие данные async всего в нескольких строках. Несоответствие между этим подходом и моим пред-GCD-подходом имеет такую ​​величину, которая достаточно велика, чтобы вызвать Too Good, чтобы быть True Alarm.

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

4b9b3361

Ответ 1

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

  • Невозможно выполнить последовательность загрузки
  • Невозможно отменить загрузку
  • Невозможно управлять возможным процессом аутентификации
  • Вы не можете легко обрабатывать ошибки, которые действительно важны, особенно в мобильных разработках, например, на 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 говорится о Concurrency Программирование, если API уже существует для выполнения асинхронных задач, используйте его, а не полагайтесь на другую технологию потоков, если это возможно)
  • Вы сохраняете преимущества NSURLConnection (обработки ошибок и т.д.).
  • но у вас также есть преимущества синтаксиса блоков, которые делают ваш код более понятным, чем при использовании методов делегата.

Ответ 2

Видеозапись сеанса WWDC 2010:

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

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

"Threads Evil ™".

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

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

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

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

Ответ 3

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