如何在上一次成功完成后将多个AFNetworking调用链接到每个运行?

时间:2012-11-21 11:09:56

标签: objective-c asynchronous objective-c-blocks afnetworking

以下方法使用AFNetworking向Web服务发送请求,并且(成功时)对响应进行操作。 AFNetworking以异步方式执行请求,并使用块来成功或失败。所以发送请求的方法看起来像这样(简化):

- (void)sendRequestForConnector:(NSString *)connector 
          success:(void (^)(NSData *responseXml))success
          failure:(void (^)(NSError *error))failure
{
  AFHTTPRequestOperation *operation = [self HTTPRequestOperationForConnector:connector];
  [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) 
  {
    [self handleSuccessForConnector:connector response:[operation responseData]];
    success([operation responseData]);
  } 
  failure:^(AFHTTPRequestOperation *operation, NSError *error) 
  {
    [self handleFailureForConnector:connector error:error];
    failure(error);
  }

  [operation start];
}

在另一个类中,此方法用于多次调用Web服务。当前一个呼叫成功时,下一个呼叫完成。此方法看起来像这样(为简洁省略了故障块):

- (void)import 
{
   [client sendRequestForConnector:@"cities" success:^{
     [client sendRequestForConnector:@"categories" success:^{
       [client sendRequestForConnector:@"categoryTranslations" success:^{
         [client sendRequestForConnector:@"products" success:^{
           [client sendRequestForConnector:@"productTranslations" success:^{

             [self finishImport];

           }];
         }];
       }]; 
     }];
   }];
}

这很有效,但是可以看出,每个webservice调用都会添加另一个嵌套的成功块处理程序。在我看来,必须有一个更好的方法来做到这一点,但我想不出一个。

最好,我想在下一次调用之前等待之前的调用完成,并使用像GCD之类的东西来异步调用整个导入方法。但是,AFNetworking并非旨在进行同步呼叫。

非常欢迎任何有关如何实现这一目标的想法。或者我目前的解决方案是否可行?

5 个答案:

答案 0 :(得分:2)

我处于相同的情况,我需要等待响应,并且需要在完成上次上传后调用ws进行上传,

有几种方法可以做到这一点

1)您可以使用dispatch_group并在完成所有操作后通知。

2)使用create semaphores逐个调用ws

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{
    dispatch_semaphore_t test = dispatch_semaphore_create(0);
    for (NSUInteger i = 0; i < self.uploadDocument.count; ++i) {
       // My custom method with block which call ws 
      [self uploadMultipleImagesUsingAFNetworkingMultipartFormatWithDocumentId:[[self.uploadDocument objectAtIndex:i] valueForKey:kDocument_DocumentId] andIndex:i withCompletionBlock:^(id responseObj, NSError *error) {

            // Your Logic 

            dispatch_semaphore_signal(test);
        }];
        dispatch_semaphore_wait(test, DISPATCH_TIME_FOREVER);

    // Here comes when your all ws finish 
      dispatch_async(dispatch_get_main_queue(), ^{
              [self.tblUpload reloadData];
              [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

        });
    }

答案 1 :(得分:1)

您可以查看octokit。他们将AFNetworking与Mantle和ReactiveCocoa相结合 - 使用ReactiveCocoa轻松,干净地进行链接。

https://github.com/octokit/octokit.objc

答案 2 :(得分:0)

我建议你看一下这个答案Better asynchronous control flow with Objective-C blocks

建议使用一些自定义解决方案来解决此问题。

答案 3 :(得分:0)

我面临同样的问题,一直在考虑引入PromiseKit&amp; AFNetworking-PromiseKit一段时间了。但我终于放弃了,并提出了一个简单而有点克服的解决方案,

所以我介绍了一个名为“step”的属性,其主要目的是为了它。然后对于每个异步调用完成时,它需要标记其步骤。然后kvo方法将整个过程移动到下一步,即 kvo方法进行流量控制。

例如,你的sendRequestForConnector:@“cities”将是第1步,@“categories”是第2步,@“categoryTranslations”是第3步,@“products”是第4步......在每次成功结束时block将步骤设置为自己的值。所以kvo会知道这一步已经完成,需要调用下一个异步方法。

kvo方法监督并控制整个过程。

compositeTemplates

到目前为止它符合我的目的,我的代码看起来更清晰。

答案 4 :(得分:-1)

如果要进行同步调用,则只需使用NSString的“stringWithContentsOfURL:”方法。因此,只需在循环中使用此代码循环遍历NSURL的NSArray。

NSError* error = nil;
NSString* htmlSource = [NSString stringWithContentsOfURL:theNSURL encoding:NSUTF8StringEncoding error:&error];
if (error) {
    // handle error
}
// parse htmlSource