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

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

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

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

Ответ 1

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

  • У меня есть один объект, заботящийся о сетевом подключении, позвольте назвать его "сетевым менеджером". Обычно этот объект является одноэлементным (созданным с помощью Matt Gallagher 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 по мере необходимости, а ядро ​​сетевого менеджера останется нетронутым.

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

Ответ 2

Вот как я обычно это делаю. У меня тоже есть одноэлементный объект, используемый для создания сетевых запросов. Для запросов, которые нужно делать часто, у меня есть 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

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

Ответ 3

Проект fully-loaded хорошо читается.

Ответ 4

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