Objective c 使用dispatch\u sync和dispatch\u async同步对嵌套异步函数的调用

Objective c 使用dispatch\u sync和dispatch\u async同步对嵌套异步函数的调用,objective-c,asynchronous,synchronization,grand-central-dispatch,Objective C,Asynchronous,Synchronization,Grand Central Dispatch,我有一个异步运行的方法,通过完成处理程序返回结果。方法调用本身立即返回,但调用完成处理程序可能需要一些时间 我想序列化对这个方法的调用,这样如果在上一次调用中没有处理完成处理程序,它就不会运行两次 现在我用的是国旗 -(void)myAsyncMethod:(void(^)(NSError *error))block { if(_isRunning) { return; // would like to queue the call } _isRunning = YE

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

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

现在我用的是国旗

-(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\u sync、async等的方法调用中使用标志。

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

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);
    });
}

或者,可以使用调度信号。

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

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);
    });
}

或者,可以使用分派信号。

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


为了回答这个隐含的问题,检查内部状态标志并没有什么错——事实上,取消就是这样工作的。如果你想在某个东西被放入队列后取消它,你最好有一个方法可以立即调用,而不是排队,它设置了一个内部的is_cancelled标志,然后在工作块/函数的开头检查,如果设置了,选择直接返回。没有取消的灵丹妙药,就像没有“如果我的工作尚未完成,请不要运行我两次”的灵丹妙药一样——你所做的基本上等同于取消,你只是在第一个仍在工作时取消后续呼叫。

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


为了回答这个隐含的问题,检查内部状态标志并没有什么错——事实上,取消就是这样工作的。如果你想在某个东西被放入队列后取消它,你最好有一个方法可以立即调用,而不是排队,它设置了一个内部的is_cancelled标志,然后在工作块/函数的开头检查,如果设置了,选择直接返回。取消没有灵丹妙药,就像如果我的工作尚未完成,就没有灵丹妙药“不要让我跑两次”——你所做的基本上等同于取消,你只是在第一个电话仍在工作时取消后续的电话。

似乎我们对这个问题的理解不同。从注释“我想在代码中对调用进行排队”中,我假设如果前一个调用仍在运行,则不应取消第二个调用,而是在前一个调用完成后排队并运行。这就是为什么我建议使用更复杂的代码。我认为这个问题在措辞上有点含糊不清。谁能说我们两人是否理解得很好呢看来我们对这个问题的理解不同。从注释“我想在代码中对调用进行排队”中,我假设如果前一个调用仍在运行,则不应取消第二个调用,而是在前一个调用完成后排队并运行。这就是为什么我建议使用更复杂的代码。我认为这个问题在措辞上有点含糊不清。谁能说我们两人是否理解得很好呢