5

我有两个想要同时执行的轻量级网络请求,然后当两者都完成后,调用一个块函数。

我创建的方法如下:

- (void)loadWithCompletion:(void (^)())completion
{
    dispatch_semaphore_t customerSemaphore = dispatch_semaphore_create(0);
    dispatch_semaphore_t communitySemaphore = dispatch_semaphore_create(0);

    dispatch_async(dispatch_queue_create("mp.session.loader", DISPATCH_QUEUE_CONCURRENT), ^(void)
    {
        [_customerClient loadCustomerDetailsWithSuccess:^(MPCustomer* customer)
        {
            [self setCurrentCustomer:customer];
            dispatch_semaphore_signal(customerSemaphore);
        } error:^(NSError* error)
        {
            LogDebug(@"Got unexpected error loading customer details: %@", error);
        }];

        [_customerClient loadCommunityDetailsWithSuccess:^(MPCommunity* community)
        {
            [self setCurrentCommunity:community];
            dispatch_semaphore_signal(communitySemaphore);
        } error:^(NSError* error)
        {
            LogDebug(@"Got unexpected error loading customer details: %@", error);
        }];
    });

    dispatch_semaphore_wait(customerSemaphore, DISPATCH_TIME_FOREVER);
    dispatch_semaphore_wait(communitySemaphore, DISPATCH_TIME_FOREVER);

    if (completion)
    {
        completion();
    }
}

. . 它最终会永远等待。我看到我的两个网络请求启动了,但是我从来没有调用来自两个客户端调用的两个回调,因此两个信号量都没有发出信号。

为什么?

4

2 回答 2

1

我想知道您创建的调度队列是否在运行块之前被销毁。但是为并发操作创建调度队列是没有意义的。而是这样做:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)...

更新:

另外,您是否检查过您的网络库没有在主队列上回调?这将导致死锁。

于 2013-09-30T08:53:28.730 回答
1

我在这里注意到的第一件事是,如果出现错误,您将永远挂起,因为您从“成功”块而不是“失败”块发出信号量。@AndyEtheridge 关于从主线程调用它然后等待也将在同一个运行循环(您正在阻塞)上传递的 NSURLConnection 回调的危险是正确的。也就是说,这可以说是用更异步的模式更好地实现。或许是这样的:

- (void)loadWithCompletion:(void (^)())completion
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_block_t workBlock = ^(void)
    {
        [_customerClient loadCustomerDetailsWithSuccess:^(MPCustomer* customer)
         {
             [self setCurrentCustomer:customer];
             dispatch_group_leave(group);
         } error:^(NSError* error)
         {
             LogDebug(@"Got unexpected error loading customer details: %@", error);
             dispatch_group_leave(group);
         }];

        [_customerClient loadCommunityDetailsWithSuccess:^(MPCommunity* community)
         {
             [self setCurrentCommunity:community];
             dispatch_group_leave(group);
         } error:^(NSError* error)
         {
             LogDebug(@"Got unexpected error loading customer details: %@", error);
             dispatch_group_leave(group);
         }];
    });

    dispatch_queue_t bgQueue = dispatch_queue_create("mp.session.loader", DISPATCH_QUEUE_CONCURRENT);

    dispatch_group_enter(group); // for the loadCustomer call
    dispatch_group_enter(group); // for the loadCommunity call

    dispatch_async(bgQueue, workBlock);

    dispatch_group_notify(group, [NSThread isMainThread] ? dispatch_get_main_queue() : bgQueue, completion);
}

这使得等待调用最终完成是异步的,如果初始调用-loadWithCompletion:来自主线程,则专门在主线程上调用完成。

于 2013-09-30T11:52:07.810 回答