使用dispatch_async和dispatch_async同步对嵌套异步函数的调用

时间:2013-09-10 12:32:01

标签: objective-c asynchronous synchronization grand-central-dispatch

我有一个异步运行的方法,并通过完成处理程序返回结果。方法调用本身返回“立即”,但完成处理程序可能需要一些时间来调用。

我想序列化对此方法的调用,这样如果在前一次调用中没有处理完成处理程序,它将不会运行两次。

现在我正在使用旗帜

-(void)myAsyncMethod:(void(^)(NSError *error))block
{
  if(_isRunning) 
  {
     return; // would like to queue the call
  }
  _isRunning = YES;
  // do some long running async work which themselves can have completion handlers and run asynchronously

  // look for ever place with a call to "block"

  _isRunning = NO;
  block(error); 
}

有没有办法在不使用dispatch_sync,async等方法调用中使用标志的情况下执行此操作。

2 个答案:

答案 0 :(得分:4)

您只需创建一次串行调度队列:

self.serialQueue = dispatch_queue_create("identifier", DISPATCH_QUEUE_SERIAL);

并提交一个用于在该队列上异步执行的块:

- (void)myAsyncMethod:(void(^)(NSError *error))block
{
    dispatch_async(self.serialQueue, ^{
        NSError *error;
        // long running task ...
        block(error);
    });
}

更新:再次阅读您的问题后,我意识到上述方法没有 如果“长时间运行的任务”本身与完成处理程序异步工作,则工作。

为了涵盖这种情况,您可以使用“调度组”:

self.group = dispatch_group_create();

-(void)myAsyncMethod:(void(^)(NSError *error))block
{
    dispatch_async(self.serialQueue, ^{
        // Start job:
        dispatch_group_enter(self.group);
        NSError *error;

        [self longRunningTaskWithCompletionHandler:^(void){
            block(error);
            // Signal that job is done:
            dispatch_group_leave(self.group);
        }];

        // Wait until job is done:
        dispatch_group_wait(self.group, DISPATCH_TIME_FOREVER);
    });
}

(或者,可以使用“调度信号量”。)

答案 1 :(得分:0)

实际上,你所做的事情已经是最简单的方法了。您不需要任何其他队列或组或信号量,或者,除了您正在做的事情之外,任何

回答隐含的问题,检查内部状态标志没有任何问题 - 实际上取消是如何工作的。如果您希望能够在排队后取消某些内容,那么您最好有一种方法可以调用(立即,不排队)设置内部" is_cancelled&# 34;然后标记您在工作区/功能的开头直接检查并选择直接返回它是否已设置。没有魔法子弹可以取消,就像没有魔法子弹一样,如果我的工作还没有完成,那就不要让我跑两次" - 你所做的事基本上等同于取消,你只是取消"取消"后续的电话,而第一个电话仍在工作。