Лучшая архитектура для приложения 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, который может сделать ваш запрос многоразовым и поддерживаемым.