通过 DispatchGroup 与 DispatchQueue 访问主队列

Posted

技术标签:

【中文标题】通过 DispatchGroup 与 DispatchQueue 访问主队列【英文标题】:Accessing main queue via DispatchGroup vs. DispatchQueue 【发布时间】:2018-03-14 20:20:07 【问题描述】:

我在后台线程上运行的类中使用 DispatchGroup。偶尔需要更新UI,所以调用如下代码:

dispatchGroup.notify(queue: .main) 
  self.delegate?.moveTo(sender: self, location: location)
  self.delegate?.updateLabel(sender: self, item: self.currentItem)

不幸的是,什么也没发生。但是,如果我通过DispatchQueue.main.async 调用相同的代码,如下所示:

DispatchQueue.main.async 
  self.delegate?.moveTo(sender: self, location: location)
  self.delegate?.updateLabel(sender: self, item: self.currentItem)

...委托调用成功。我的印象是dispatchGroup.notify(queue: .main) 相当于DispatchQueue.main.async

为什么这些不一样?

【问题讨论】:

【参考方案1】:

在您调用notify(queue:) 时,您的dispatchGroup 是否为空(即没有块正在运行)?如果没有,正如documentation 所说dispatchGroup.notify(queue:)

当一组先前提交的块对象完成时,安排要提交到队列的工作项。

这意味着只有在最后一次 leave() 调用之后,当组变为空时,才会执行您的闭包。当然,enter()s 和 leave()s 必须平衡。

考虑以下示例:

let group = DispatchGroup()

group.enter()
someLongRunningTask() 
  // completion callback
  group.leave()


group.enter()
anotherLongRunningTask() 
  // completion callback
  group.leave()


group.notify(queue: .main) 
  print("all set")

在此示例中,all set 将仅在使用 group.leave() 执行的两个回调之后打印。

另一方面,DispatchQueue.main.async() 会立即将块提交到目标队列,但它不一定会在此之后立即开始 - 例如,可能会运行带有 .barrier 标志的 async 块。

更新:使用DispatchQueue 实现上述示例(希望它能让事情变得清晰):

let group = DispatchGroup()

group.enter()
someLongRunningTask() 
  // completion callback
  group.leave()


group.enter()
anotherLongRunningTask() 
  // completion callback
  group.leave()


group.wait() // waits synchronously for the submitted work to complete
DispatchQueue.main.async 
  print("all set")

【讨论】:

谢谢你这么详细的解释!这让我远离了。

以上是关于通过 DispatchGroup 与 DispatchQueue 访问主队列的主要内容,如果未能解决你的问题,请参考以下文章

Swift 伪原子并发同步代码引起 DispatchGroup.leave() 方法不平衡调用导致 App 崩溃的解决

DispatchGroup 逻辑工作流

为啥 DispatchGroup 会干扰主队列?

下载 Firebase 存储数据时,DispatchGroup 未正确执行

DispatchGroup 等待 Firestore 查询完成

等待循环完成,DispatchGroup 使用 Swift 从 firebase 获取数据