Как пакетный запрос с AFNetworking 2?
Итак, я переписываю приложение для iOS 7 с AFNetworking 2.0, и я столкнулся с проблемой отправки пакета запросов сразу и отслеживания их прогресса. В старом AFNetworking был enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:
метод на AFHTTPClient
, это явно рефакторизовано, и я немного смущен тем, как вставлять несколько запросов.
Я создал подкласс AFHTTPSessionManager
, и я использую методы POST:...
и GET:...
для связи с сервером. Но я не могу найти что-либо в коде и/или документах для того, чтобы вставлять несколько запросов одновременно, как со старым AFHTTPClient
.
Единственное, что я могу найти, это недокументированный метод batchOfRequestOperations:progressBlock:completionBlock:
на AFURLConnectionOperation
, но это похоже на способ iOS 6 этого.
Очевидно, что я пропускаю что-то в новой концепции NSURLSession
, которую я должен использовать для пакетных запросов или просмотра новой функции AFNetworking. Надеюсь, кто-то может помочь мне на правильном пути здесь!
tl; dr: Как отправить пакет запросов с моим подклассом AFHTTPSessionManager
?
Ответы
Ответ 1
Спасибо Sendoa за ссылку на вопрос GitHub, где Мэтт объясняет, почему эта функциональность больше не работает. Существует ясная причина, почему это невозможно с новой структурой NSURLSession
; Задачи просто не являются операциями, поэтому старый способ использования зависимостей или партий операций не будет работать.
Я создал это решение, используя dispatch_group
, который позволяет выполнять пакетные запросы с помощью NSURLSession
, вот (псевдо) код:
// Create a dispatch group
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 10; i++) {
// Enter the group for each request we create
dispatch_group_enter(group);
// Fire the request
[self GET:@"endpoint.json"
parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
// Leave the group as soon as the request succeeded
dispatch_group_leave(group);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
// Leave the group as soon as the request failed
dispatch_group_leave(group);
}];
}
// Here we wait for all the requests to finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// Do whatever you need to do when all requests are finished
});
Я хочу посмотреть что-нибудь, что упростит работу и обсудит с Мэттом, если это что-то (когда реализовано красиво), которое можно объединить в AFNetworking. На мой взгляд, было бы здорово сделать что-то подобное с самой библиотекой. Но я должен проверить, когда у меня есть свободное время.
Ответ 2
Просто обновляю нить... У меня была такая же проблема, и после некоторых исследований я нашел несколько хороших решений, но я решил придерживаться этого:
Я использую проект под названием Bolts. Итак, для того же образца выше, опубликованного @Mac_Cain13, это будет:
[[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) {
BFTask *task = [BFTask taskWithResult:nil];
for (int i = 0; i < 10; i++) {
task = [task continueWithBlock:^id(BFTask *task) {
return [self executeEndPointAsync];
}];
}
return task;
}] continueWithBlock:^id(BFTask *task) {
// Everything was executed.
return nil;
}];;
- (BFTask *) executeEndPointAsync {
BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
[self GET:@"endpoint.json" parameters:nil
success:^(NSURLSessionDataTask *task, id responseObject) {
[task setResult:responseObject];
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
[task setError:error];
}];
}];
return task.task;
}
В основном, он укладывает все задачи, ждет и разворачивается, пока не будет больше задач, и после того, как все будет завершено, будет выполнен последний блок завершения.
Другим проектом, который делает то же самое, является RXPromise, но для меня более понятный код Bolts.
Ответ 3
Для request
, который может быть post
или get
, вы можете использовать AFNetworking 2.0
для пакетного управления, поскольку сначала вам нужно создать операцию следующим образом:
//Request 1
NSString *strURL = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters = your parameters here
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL parameters:dictParameters error: nil];
AFHTTPRequestOperation *operationOne = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationOne = [AFHTTPResponseSerializer serializer];
[operationOne setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//do something on completion
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"%@",[error description]);
}];
//Request 2
NSString *strURL1 = [NSString stringWithFormat:@"your url here"];
NSLog(@"scheduleurl : %@",strURL);
NSDictionary *dictParameters1 = your parameters here
NSMutableURLRequest *request1 = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:strURL1 parameters:dictParameters1 error: nil];
AFHTTPRequestOperation *operationTwo = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
operationTwo = [AFHTTPResponseSerializer serializer];
[operationTwo setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//do something on completion
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"%@",[error description]);
}];
//Request more here if any
Теперь выполните пакетную операцию следующим образом:
//Batch operation
//Add all operation here
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:@[operationOne,operationTwo] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations)
{
NSLog(@"%i of %i complete",numberOfFinishedOperations,totalNumberOfOperations);
//set progress here
yourProgressView.progress = (float)numberOfFinishedOperations/(float)totalNumberOfOperations;
} completionBlock:^(NSArray *operations)
{
NSLog(@"All operations in batch complete");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];
Ответ 4
В AFNetworking 2.0 AFHTTPClient
был разделен на AFHTTPRequestOperationManager
и AFHTTPSessionManager
, поэтому, возможно, вы можете начать с первого, у которого есть свойство operationQueue
.
Ответ 5
В настоящее время задачи NSURLSession
не подходят для того же типа операций запроса шаблонов. См. Ответ от Mattt Thompson здесь относительно этой проблемы.
Прямой ответ: если вам нужны зависимости или партии, вам все равно придется использовать операции запроса.