我正在尝试在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!")
}
答案 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)
在执行本身是同步的任务时,将使用对您使用的 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