48

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

В настоящее время я создаю одноразовые «запросчики», которые сохраняются делегатом приложения и сидят рядом с прослушиванием NSNotifications, которые сигнализируют, что запрос должен быть сделан; они делают запрос, прислушиваются к ответу и отправляют новую NSNotification с данными ответа. Это решает большинство моих проблем, но не изящно обрабатывает неудавшиеся запросы или одновременные запросы одному и тому же запросу.

У кого-нибудь есть какие-либо успехи в создании четкой архитектуры OO для создания множества различных типов запросов в приложении iOS?

+2

Хороший вопрос: я также изучал ответ на этот вопрос, так же как и тот, кто создал диспетчер соединений для NSURLConnection, который хорошо работает для одного соединения, но не так хорошо для нескольких. –

ответ

69

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

  • У меня есть один объект заботится о связности сети, давайте назовите его «сетевым менеджером». Обычно этот объект является одноэлементным (созданным с использованием Matt Gallagher's Cocoa singleton macro).
  • Поскольку вы используете ASIHTTPRequest (который я всегда делаю, замечательный API), я добавляю внутри сетевой диспетчер ASINetworkQueue ivar. Я делаю диспетчер сети делегатом этой очереди.
  • Я создаю подклассы ASIHTTPRequest для каждого вида сетевых запросов, которые требуется моему приложению (как правило, для каждого взаимодействия REST или конечной точки SOAP). Это имеет другое преимущество (см. Ниже для получения более подробной информации).
  • Каждый раз, когда один из моих контроллеров требует некоторых данных (refresh, viewDidAppear и т. Д.), Сетевой менеджер создает экземпляр требуемого подкласса ASIHTTPRequest и затем добавляет его в очередь ,
  • ASINetworkQueue заботится о проблемах с пропускной способностью (в зависимости от того, находитесь ли вы на 3G, EDGE или GPRS или Wi-Fi, у вас больше пропускной способности, и вы можете обрабатывать больше запросов и т. Д.). Это делается в очереди, которая крута (по крайней мере, это одна из вещей, которые я понимаю, эта очередь делает, надеюсь, я не ошибаюсь :).
  • Всякий раз, когда запрос заканчивается или выходит из строя, вызывается диспетчер сети (помните, что диспетчер сети является делегатом очереди).
  • Сетевой менеджер не знает приседания о том, что делать с результатом каждого запроса; следовательно, он просто вызывает метод по запросу! Помните, что запросы являются подклассами ASIHTTPRequest, поэтому вы можете просто поместить код, который управляет результатом запроса (как правило, десериализация JSON или XML в реальные объекты, запуск других сетевых подключений, обновление хранилищ Core Data и т. Д.). Ввод кода в каждый отдельный подзадач запроса с использованием полиморфного метода с общим именем по классам запросов позволяет легко отлаживать и управлять IMHO.
  • Наконец, я уведомляю контроллеры выше об интересных событиях с использованием уведомлений; использование протокола делегата - это не очень хорошая идея, потому что в вашем приложении обычно есть много контроллеров, которые разговаривают с вашим сетевым менеджером, а затем уведомления более гибкие (вы можете иметь несколько контроллеров, отвечающих на одно и то же уведомление и т. д.).

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

Надеюсь, это поможет!

+0

хороший ответ! как вы тестируете свою систему? другая большая моя забота придумывает архитектуру, которая легко тестируется на единицу. – kevboh

+0

спасибо, отличное объяснение. – Epaga

+5

Одна быстрая вещь, которая приходит на ум, вы можете использовать блоки вместо уведомлений, если у вас есть только один класс, который интересуется вашим ответом. –

0

fully-loaded проект хороший читать.

+0

Я видел полностью загруженную до того, как он справляется с конкретной проблемой, но я ищу решение, которое обрабатывает разные типы запросов, которые имеют разные ответы. Способ загрузки запросов с полной загрузкой аналогичен тому, что я подробно описал в моем вопросе, с nsnotifications и asihttprequest, делающим тяжелый подъем. Я ищу что-то более расширяемое и надежное, даже если это просто творческий способ организации уведомлений и запросов. – kevboh

+1

Другим примером кода, на мой взгляд, является папка «Networking» в образце MVCNetworking от Apple, и у меня нет никакого опыта делать какие-либо комментарии. – ohho

+0

Интересно. Я должен проверить это. – kevboh

1

Вот как я обычно это делаю. У меня тоже есть одноэлементный объект, используемый для создания сетевых запросов. Для запросов, которые нужно делать часто, у меня есть NSOperationQueue, который принимает AFHTTPRequestOperations (или AFJSONRequestOperations), поскольку я обычно использую AFNetworking для запросов. Для них существует свойство завершенияBlock и failBlock, которое выполняется при успешном завершении или неудаче запроса. На моем объекте singleton у меня был бы способ инициирования конкретного сетевого запроса, и в качестве параметров для этого метода я бы включил блок успеха и отказа, который можно передать в блоки, определенные в методе. Таким образом, все приложение может выполнить сетевой запрос, а область приложения в этой точке доступна для singleton в блоке, который передается методу. Например ... (с использованием ARC)

 @implementation NetworkManager 

    -(void)makeRequestWithSuccess:(void(^)(void))successBlock failure:(void(^)(NSError *error))failureBlock 

    { 
     NSURL *url = [NSURL URLWithString:@"some URL"]; 

     NSURLRequest *request = [NSURLRequest requestWithURL:url]; 

     AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 

     [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
      [responseObject doSomething]; 

      if (successBlock) 
       dispatch_async(dispatch_get_main_queue(), successBlock); 

     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 

      if (failureBlock) 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        failureBlock(error); 
       }); 
     }]; 

     [self.operationQueue addOperation:op]; 
    } 
@end 

И вы всегда можете сделать блок успеха, чтобы выполнить любые параметры, необходимые для прохождения.

0

Попробуйте STNetTaskQueue, что может сделать ваш запрос многоразовым и ремонтопригодным.