Множественный запрос AFHTTPClient

У меня есть подкласс AFHTTPClient Основная идея в том, что я вызываю все API через свой синглтон подкласса AFHTTPClient, и все запросы проходят через 1 точку для обработки ошибок и отображения HUD. Это точка входа для каждого вызова API:

-(void) makeRequestWithPath:(NSString*) path andParams:(NSDictionary*) params 
                    success:(void (^)( id JSON, AFHTTPRequestOperation *operation)) success
                    failure:(void (^)( NSError *error)) failure

И у меня есть много методов для вызовов API, что-то вроде этого:

-(void) getListMainTreeWithSuccess:(void (^)( id JSON, AFHTTPRequestOperation *operation)) success
                       failure:(void (^)( NSError *error)) failure
{

[self makeRequestWithPath:@"objects/selectlist" andParams:nil success:^(id JSON, AFHTTPRequestOperation *operation) {
    success(JSON,operation);
} failure:^(NSError *error) {
    failure(error);
}];

}

Это прекрасно работает для моих нужд. Но я столкнулся с проблемой, что мне нужно сделать последовательный запрос в цикле через мой подкласс AFHTTPClient и выполнить какое-то действие, когда все они будут завершены, я нашел метод

-(void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests
                                      progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
                                    completionBlock:(void (^)(NSArray *operations))completionBlock

который должен решить мою проблему, но проблема в том, что я вызываю все методы через AFHTTPClient и его методы getPath: и postPath: и предыдущий способ заставляет меня переписывать все и делает мой подкласс совершенно бесполезным, потому что мне нужно добавить туда NSArray из AFHTTPRequestoperation, который невозможно построить или извлечь из моего подкласса и моих методов. Раньше я пытался использовать __block для синхронизации запросов с семафором и чем-то еще, но мне не удалось получить то, что мне нужно, пожалуйста, помогите мне!

ОБНОВЛЕНИЕ: кажется, что невозможно даже использовать метод enqueueBatchOfHTTPRequestOperations (даже с переписыванием всего моего кода), потому что для этого метода требуется массив операций http-запроса, но это невозможно построить POST-запрос с ними.


person KysokZla    schedule 10.01.2014    source источник
comment
Вы можете отправлять сообщения с помощью enqueueBatchOfHTTPRequestOperations   -  person Mike Pollard    schedule 10.01.2014


Ответы (2)


Я решил эту проблему с помощью системы ожидания загрузки с увеличением / уменьшением и привязал к этому HUD.

[networkStatus beginNetworkActivity];
[client someRESTActionWithCompletion:^(id object, NSError *error) {
    [networkStatus endNetworkActivity];

    if (error) {
        // Handle the error ...
    }

    if (![networkStatus hasNetworkActivity]) {
        // All downloads have finished
    }
}];

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

Статус сети ведет внутренний счетчик. -beginNetworkActivity увеличивает счетчик, если счетчик был 0, то отображает HUD. -endNetworkActivity уменьшает счетчик, если счетчик становится 0, то он закрывает HUD. -hasNetworkActivity возвращает YES, если счетчик больше 0.

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

person Jeffery Thomas    schedule 10.01.2014
comment
Спасибо за ответ, но у меня нет проблем с отображением HUD, я уже понял это в своем подклассе AFHTTPClient. У меня проблема с выполнением многих запросов через AFHTTPClient в одном месте, и поэтому я знаю, когда именно ВСЕ из них будут завершены, чтобы я мог выполнить дальнейший код. С ASIHTTP это было легко, потому что все ответы шли к одному единственному методу, и все запросы выполнялись один за другим, поэтому я точно знал, когда все они были закончены. - person KysokZla; 14.01.2014
comment
@KysokZla [networkStatus hasNetworkActivity] вернет NO, когда все запросы будут выполнены. Это индикатор, который вы ищете. - person Jeffery Thomas; 15.01.2014

Опять же, как сказал @MikePollard, создайте AFHTTPRequestOperation, используя

[AFHHTPClient HTTPRequestOperationWithRequest:success:failure:]

Для этого метода создайте NSURLRequest с помощью (или используйте другой, выберите подходящий вам). Здесь же можно указать, какой метод использовать POST, GET или любой другой.

[AFHTTPClient requestWithMethod:
                           path:
                     parameters:]

После этого сохраните все операции в NSArray и запланируйте их, используя:

[AFHTTPClient enqueueBatchOfHTTPRequestOperationsWithRequests:
                                                progressBlock:
                                              completionBlock:]

Пример кода:

NSMutableArray *ops = [NSMutableArray new];
NSMutableURLRequest *request1 = [[AFHTTPClient sharedClient] requestWithMethod:@"GET"
                                                                          path:@"MyEndpoint"
                                                                    parameters:@{@"key1": @"value"}];
AFHTTPRequestOperation *op1 = [[AFHTTPClient sharedClient] HTTPRequestOperationWithRequest:request1
                                                                                   success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                                                                       NSLog(@"Success!");
                                                                                   }
                                                                                   failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                                                                       NSLog(@"Failure!");
                                                                                   }];
[ops addObject:op1];

NSMutableURLRequest *request2 = [[AFHTTPClient sharedClient] requestWithMethod:@"POST"
                                                                          path:@"MyAnotherEndpoint"
                                                                    parameters:@{@"key2": @(104)}];
AFHTTPRequestOperation *op2 = [[AFHTTPClient sharedClient] HTTPRequestOperationWithRequest:request2
                                                                                   success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                                                                       NSLog(@"Success!");
                                                                                   }
                                                                                   failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                                                                       NSLog(@"Failure!");
                                                                                   }];
[ops addObject:op2];
[[AFHTTPClient sharedClient] enqueueBatchOfHTTPRequestOperationsWithRequests:ops
                                                               progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
                                                                   NSLog(@"numberOfFinishedOperations: %d totalNumberOfOperations %d",
                                                                         numberOfFinishedOperations,
                                                                         totalNumberOfOperations);
                                                               }
                                                             completionBlock:^(NSArray *operations) {
                                                                 NSLog(@"All operation compelted!");
                                                             }];
person Vytautas    schedule 10.01.2014
comment
Извините, я не могу понять ваш ответ (не могли бы вы предоставить простой код, например, с двумя разными запросами POST с двумя разными параметрами для каждого и выполнением их с вашим подходом. Буду очень признателен за вашу помощь - person KysokZla; 14.01.2014
comment
Точно я не понимаю, как можно сохранить объект HTTPRequestOperation через [AFHHTPClient HTTPRequestOperationWithRequest: успех: отказ:], потому что этот объект доступен только в блоке успеха, и этот блок появляется только после завершения операции. Я где-то ошибся? - person KysokZla; 14.01.2014
comment
Да, вы что-то упустили, всегда полезно взглянуть на документацию или заголовочный файл. Но в любом случае, я добавил пример, надеюсь, теперь вы поняли идею. - person Vytautas; 14.01.2014
comment
Полезно знать, в вашем примере есть ошибка: enqueueBatchOfHTTPRequestOperationsWithRequests принимает массив NSURLRequest. enqueueBatchOfHTTPRequestOperations фактически принимает массив AFHTTPRequestOperation. Вы смешиваете оба в своем коде, это не сработает. - person Ben; 02.07.2015