Лучшая архитектура для приложения iOS, которое делает много сетевых запросов? - PullRequest
49 голосов
/ 27 января 2011

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

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

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

Ответы [ 4 ]

69 голосов
/ 28 января 2011

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

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

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

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

1 голос
/ 14 января 2013

Вот как я обычно это делаю.У меня тоже есть одноэлементный объект, используемый для сетевых запросов.Для запросов, которые нужно делать часто, у меня есть NSOperationQueue, который принимает AFHTTPRequestOperations (или AFJSONRequestOperations), поскольку я обычно использую AFNetworking для выполнения запросов.Для них есть свойство завершение и сбой, который выполняется при успешном выполнении или сбое запроса.В моем одноэлементном объекте у меня был бы метод для инициирования конкретного сетевого запроса, и в качестве параметров этого метода я бы включил блок успеха и неудачи, который можно передать в блоки, определенные в методе.Таким образом, все приложение может сделать сетевой запрос, и область приложения в этот момент доступна для одиночного блока в блоке, который передается методу.Например ... (с использованием 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 голосов
/ 09 февраля 2015

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

0 голосов
/ 27 января 2011

Хорошо загруженный проект .

...