dispatchqueue .main.async在重复挂起之后,但在使用sleep时不会挂起 &g



我正在尝试使用Swift为Macos创建一个机器人过程自动化工具。用户创建一个自动化,它是Step对象的数组,然后播放它。Step的一个子类是Pause,它应该暂停执行给定的秒数。

由于某种原因,当我在Pause类中使用DispatchQueue.main.asyncAfter()方法时,执行会挂起。通常第一次运行自动化是没问题的,但是当它重复运行时,它最终会挂起更长的时间。当我使用sleep()时,错误就消失了。

关于这个bug的另一个奇怪的事情是,当我打开Xcode试图查看发生了什么,挂起解决并继续执行。我想知道这个过程是否以某种方式进入背景,然后DispatchQueue.main.asyncAfter()不起作用。我已经尝试更改信息。应用程序未在后台运行;设置为"YES",但这没有任何效果。

使用sleep()的问题是它阻塞了UI线程,所以用户不能停止自动化,如果他们需要。我用DispatchQueue尝试了很多不同的线程变体,但它似乎总是挂在重复执行的某个地方。我也尝试过使用Timer.scheduledTimer()而不是DispatchQueue,但那也挂起了。我肯定我错过了一些简单的东西,但是我想不出来。

创建步进阵列和启动自动化

class AutomationPlayer {

static let shared = AutomationPlayer()

var automation: Automation?
var stepArray: [Step] = []

func play() {
// Create array of steps
guard let steps = automation?.steps, let array = Array(steps) as? [Step] else { 
return 
}
// If the automation repeats, add more steps to array.
for _ in 0..<(automation?.numberOfRepeats ?? 1) {
for (index, step) in array.enumerated() {
stepArray.append(step)
}
}
// Add small delay to allow window to close before execution.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) { [weak self] in
self?.execute(index: 0)
}
}

private func execute(index: Int) {
let step = stepArray[index]

executeStep(step: step) { [weak self] success, error in
guard error == nil else { return }
let newIndex = index + 1
if newIndex < self?.stepArray.count ?? 0 {
//Need a small delay between steps otherwise execution is getting messed up.
usleep(400000)
self?.execute(index: newIndex)
} else {
self?.stepArray = []
}
}
}

private func executeStep(step: Step?, completionHandler: @escaping (Bool, Error?) -> Void) -> Void {
step?.execute(completionHandler: { [weak self] success, error in
guard error == nil else {
completionHandler(false, error)
return
}
completionHandler(true, nil)
})
}
<<p>暂停类/strong>
@objc(Pause)
public class Pause: Step {

override func execute(completionHandler: @escaping (Bool, Error?) -> Void)  {
print("Pause for: (self.time) seconds")
// This will eventually hang when the automation repeats itself
DispatchQueue.main.asyncAfter(deadline: .now() + Double(self.time)) {
completionHandler(true, nil)
})
// This will also hang
Timer.scheduledTimer(withTimeInterval: self.time, repeats: false)             { timer in
completionHandler(true, nil)
}
// If I use this instead, the automation repeats just fine
sleep(UInt32(self.time))
completionHandler(true, nil)
}
}

我想我明白了。MacOS在一段时间后将我的应用程序放入AppNap,这会导致DispatchQueue.main.async()停止工作。由于某些原因,当你使用sleep()

时,AppNap不会影响延迟我在这里找到了答案

这个答案有点老了。我正在使用SwiftUI来构建我的mac应用程序,所以我添加了这个@main结构体

@main
struct Main_App: App {
@State var activity: NSObjectProtocol?
var body: some Scene {
WindowGroup("") {
MainWindow()
.onAppear {
activity = ProcessInfo().beginActivity(options: .userInitiated, reason: "Good Reason")
}
}
}

这似乎阻止了应用程序进入AppNap和自动化继续。虽然很丑,但是很好用。

相关内容

  • 没有找到相关文章