在iOS中等待几个网络异步调用

时间:2013-08-01 04:03:10

标签: ios asynchronous nsurlconnection grand-central-dispatch nsnotificationcenter

从视图控制器,作为按钮操作的结果,我需要创建一个管理一组异步远程服务调用的自定义对象,并调用触发这些服务调用的此类对象的方法。我需要视图控制器等待所有异步网络操作完成以更新其视图。由于网络操作是异步的,因此在完成所有操作后,我不知道如何从管理此任务的自定义对象通信到视图控制器。

这是我目前的代码。视图控制器中的代码片段如下所示(当前未使用result var):

- (void)loadData
{
   BOOL __block result = NO;

   dispatch_queue_t queue = dispatch_queue_create(dataLoadQueue, NULL);
   dispatch_async(queue,^{

      Loader *loader = [[Loader alloc] init];
      [loader loadData];

      dispatch_async(dispatch_get_main_queue(), ^{

        if (result) {
            // Update view and notify success
        }
        else {
            // Update view and notify error
        }
      });
   });

   dispatch_release(queue);
}

这是loader自定义对象端:

- (void)loadData
{
   if ([Reachability checkNetStatus]) {

      Service1 *service1 = [[Service1 alloc] init];
      [service1 callAsyncService];

      Service2 *service2 = [[Service2 alloc] init];
      [service2 callAsyncService];

      // More service calls
   }

   else {
      // Notify network not reachable
   }
}

对象service1, service2... serviceN符合NSURLConnectionDelegate,我通过connectionDidFinishLoading:NSNotificationCenter对象正在侦听此类通知,通知他们已在loader中完成)。然后,我不知道使loader等待所有网络操作的正确方法是什么,并通知视图控制器。

提前致谢

3 个答案:

答案 0 :(得分:0)

如果要等到异步任务完成,可以使用信号量。看下面的例子,逻辑非常简单。我认为你很容易适应你的情况。

//create the semaphore
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

[objectManager.HTTPClient deletePath:[address addressURL] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {

      //some code here executed in background

        dispatch_semaphore_signal(semaphore); //sends a notification to release the semaphore

    }failure:^(AFHTTPRequestOperation *operation, NSError *error) {

       //some other code here also executed in background

        dispatch_semaphore_signal(semaphore); //sends a notification to release the semaphore
    }];


//holds the thread until the dispatch_semaphore_signal(semaphore) is send
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
{
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}

答案 1 :(得分:0)

你可能有很多方法可以做到这一点。首先,我认为在视图控制器中不需要使用GCD - 加载器已经异步执行,因此加载器的创建很快。

至于Loader如何知道其所有网络操作何时完成,你可以在一个可变数组中保存一个字符串列表,比如“1 done”,“2 done”等等,这与发送的字符串相同在connectionDidFinishLoading中调用的通知的用户信息中:所有服务都可以发送相同的通知,但具有不同的用户信息。在观察者的选择器中,删除与用户信息中的字符串相同的字符串,并检查该数组是否为空 - 如果是,则表示所有服务都已完成。此时,我将使用委托方法将数据传递回视图控制器。 Loader中有这样的东西:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.doneStrings = [@[@"1 done", @"2 done", @"3 done", @"4 done"] mutableCopy];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationReceived:) name:@"SeriveFinishedNotification" object:nil];
}

-(void)notificationReceived:(NSNotification *) aNote {
    [self.doneStrings removeObjectIdenticalTo:[aNote.userInfo objectForKey:@"doneString"]];
    if (self.doneStrings.count == 0)
        [delegate doSomethingWithTheData: theData];
}

您可能需要处理其他一些事情,例如处理某些网络操作失败的情况。

答案 2 :(得分:0)

您还没有分享这些异步请求如何工作的详细信息,但另一种方法是将这些异步请求NSOperation对象提交给NSOperationQueue。 (AFNetworking是此类实现的一个示例。)执行此操作时,您可以创建另一个NSOperation,以便在网络请求操作完成时触发,方法是使其依赖于这些网络请求操作。因此,它仅在所有网络请求完成时运行。使用基于NSOperation的解决方案也可以享受其他好处(例如,您可以使用setMaxConcurrentOperationCount来享受并发性,但不能在任何给定时间运行过多的并发请求。)

参考