具有DispatchGroup的异步功能

时间:2020-08-02 23:50:58

标签: swift

我正在尝试在Playgrounds中设置动画,并在完成后在调试器中弹出一条简单消息。

这样,.notify就会出现在开头。动画功能通过DispatchQueue.main.async(group:animationGroup)内部后会出现吗?

以下是提供的代码:

import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

extension UIView {
  static func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void, group: DispatchGroup, completion: ((Bool) -> Void)?) {
     
  }
}
let animationGroup = DispatchGroup()
// A red square
let view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view.backgroundColor = UIColor.red
// A yellow box
let box = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
box.backgroundColor = UIColor.yellow
view.addSubview(box)
PlaygroundPage.current.liveView = view

DispatchQueue.main.async(group: animationGroup) {

  UIView.animate(withDuration: 1, animations: {
    // Move box to lower right corner
    box.center = CGPoint(x: 150, y: 150)
    }, completion: {
      _ in
      UIView.animate(withDuration: 2, animations: {
        // Rotate box 45 degrees
        box.transform = CGAffineTransform(rotationAngle: .pi/4)
        }, completion: .none)
  })

  UIView.animate(withDuration: 4, animations: { () -> Void in
    // Change background color to blue
    view.backgroundColor = UIColor.blue
  })
}

animationGroup.notify(queue: DispatchQueue.main) {
  print("Animations Completed!")
}

2 个答案:

答案 0 :(得分:0)

首先,引用documentation

通知(队列:工作:)

安排一组先前提交的块对象完成后将要提交给队列的工作项目。

基本上,没有“先前”提交的块,因此您的notify块会立即被调用。发生这种情况是因为您将工作项添加到了DispatchQueue.main.async中的组中。您可以在DispatchQueue.main.async(group: animationGroup)方法内在notify内添加一个打印件并添加另一个打印件来进行检查。第二个将首先打印。

最重要的是,在DispatchGroup.main.async中调用异步函数是有问题的,因为该工作项将立即进入,然后将您的异步工作分派到另一个线程,该工作项将立即离开,甚至尽管您的异步工作尚未完成。

要解决此问题,必须在开始异步操作时调用animationGroup.enter(),然后在完成后调用animationGroup.leave()。此外,您还必须将代码从DispatchGroup.main.async中删除。如果进行了这些更改,则notify调用达到平衡时,将执行enter/leave块。

答案 1 :(得分:0)

在执行本身是同步的任务时,将使用对您使用的Edit Reset form after submit API的调用。例如。假设您要使用一些缓慢的同步API处理一堆图像,但希望在后台线程上并行运行此图像,以避免阻塞主线程。然后,您将使用write() API:

async(group:execute:)

不过,在这种情况下,各个基于块的let group = DispatchGroup() for image in images { DispatchQueue.global().async(group: group) { self.process(image) } } group.notify(queue: .main) { // all done processing the images } 动画API调用是异步运行的。因此,您不能使用此UIView模式。在开始每个异步过程之前,您必须先手动async(group:execute:),然后在相应的完成闭包内部enter,将它们一对一地匹配:

leave