我在 ViewDidAppear
中调用一个动画,稍后在 ViewDidAppear
中我调用一个创建多个 UIImage 对象数组并需要 4-5 秒的函数完成。
同时,动画只有 0.8 秒长,并且有一个完成 block :
UIView.animate(withDuration: 0.8, delay: 0.0, options: UIViewAnimationOptions(), animations: {
self.myView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
}, completion: { finished in
self.nextTask()
})
问题是完成 block 不会在 0.8 秒后运行 - 它直到前面的代码完成后才运行。
除了 在后台线程中使用 DispatchQueue.global(qos: .background).async
运行该代码,我还有什么可以做的吗?或者有没有办法提高后台线程的完成速度?
如果在后台线程中完成,我的动画不会中断,但在后台完成需要更长的时间 - 大约 20-30 秒而不是 4-5 秒。
感谢您在这里分享的任何帮助!
最佳答案
I am calling a function which creates several arrays of UIImage objects and takes 4-5 seconds to complete
你绝对不能在主线程上运行它。现代设备上的刷新帧为 1/120 秒。您不得导致帧丢失。发生这种情况时,您正在阻止用户交互。屏幕将被卡住,看门狗进程将当场杀死您的应用程序。 (不幸的是,模拟器没有向您显示,也没有从设备上的 Xcode 运行;但是如果您在设备上运行应用程序,请停止它,然后从设备而不是从 Xcode 运行它,你会明白我的意思。)
The issue is that the completion block doesn't run 0.8 seconds later - it doesn't run until AFTER the previous code completes.
正如您所猜测的,这里存在重入问题。您需要离开主线程以允许完成 block 发生。我真的很惊讶动画甚至开始(是吗?)。当您仍在主线程上运行代码时,什么都不会发生。
您可以调用 async_after
并短暂延迟以暂时跳出主线程,然后重新进入主线程,足够长的时间让刷新帧发生,这样系统就可以做一些工作。但这只是让动画开始的一种方式。一旦您回到主线程,您将再次阻塞它。
至于速度:.background
的 QOS 是最慢的选择,因此您得到了您想要的。不过,一般来说,不要使用全局队列;制作自己的队列。我无法想象你正在做的事情会花这么长时间,也许这才是你真正应该问的问题,但你绝对不能在主线程上做。
关于Swift:运行代码会阻止其他代码直到完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50884634/