我的代码中的 GCD 有一个非常奇怪的情况,这是一个最小的可重现代码:
- (void)runMyCode {
__block BOOL completed = NO;
[self runSomeAsyncAPI:^{
completed = YES;
}];
while (!completed) {
[NSRunLoop.currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
[self runMyCode];
});
}
完成块根本没有被调用。但如果我不使用dispatch_async,它就会起作用。这很奇怪。
问题在于它将
runMyCode
分派到串行队列,旋转直到设置 complete
为止。因此,在通过 dispatch_async
分派的代码完成之前,分派到同一串行队列的任何其他内容都无法运行。当然,运行循环可以处理事件,但串行队列被占用。 dispatch_after
(将设置 complete
)无法在同一个串行队列上运行。
有多种方法可以解决这个问题:
运行循环上的旋转是一种早于 GCD 的技术,现在是一种反模式。最好的解决方案是放弃它并采用异步模式。如果我们了解您旋转的原因,我们可能可以提供一些合理的、现代的替代方案。
您可以对初始
dispatch_async
和后续 dispatch_after
使用不同的队列。
您可以使用并发队列(创建自己的队列或使用全局队列)。