我有一个异步运行的方法,并通过完成处理程序返回结果。方法调用本身返回“立即”,但完成处理程序可能需要一些时间来调用。
我想序列化对此方法的调用,这样如果在前一次调用中没有处理完成处理程序,它将不会运行两次。
现在我正在使用旗帜
-(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等方法调用中使用标志的情况下执行此操作。
答案 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;然后标记您在工作区/功能的开头直接检查并选择直接返回它是否已设置。没有魔法子弹可以取消,就像没有魔法子弹一样,如果我的工作还没有完成,那就不要让我跑两次" - 你所做的事基本上等同于取消,你只是取消"取消"后续的电话,而第一个电话仍在工作。