AKMetronome倒计时,如何从后台线程发布到主线程启动录音机?

AKMetronome countdown, how to publish to main thread from background thread to start recorder?

我一直在研究如何使用 AudioKit 库实现节拍器倒计时,但 运行 遇到与线程和我的实现相关的问题。

我的实现使用 AudioKit AKMetronome,一种处理 metronome.start 的方法,metronome.callback 处理程序在给定数量的小节完成后启动 recording

init () {
  metronome.callback = handler
}

func record () {
    self.metronome.start()
}

处理程序及时计算节拍器位置,如果所需的小节数完成(倒计时),记录器将启动。

不幸的是,运行 AKNodeRecorder.recordAKMetronome.callback handler 导致警告信息:

Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.

因此,在 metronome.callback 处理程序中开始录制的调用通过 GCD API:

传递到主线程
            DispatchQueue.main.sync {
                do {
                    try self.recorder.record()
                } catch {
                    print("[ERROR] Oops! Failed to record...")
                }
            }

我已经使用 .sync 阻塞方法来尽可能立即解决计算,因为 时序在音频应用程序中至关重要(理想情况下,调用应在实时线程中执行);我的理解是 GCP API main thread 提供最高优先级,但我不确定这是否是对时间敏感的应用程序的最佳选择?

如果可能,想从其他用户那里得到一些反馈或指导,谢谢!

好的,所以实际问题与节拍器或倒计时无关?您真正想知道的是:从后台线程使用 sync 会让我更快地进入主线程吗?

如果是:基本没有。这不是 sync 的用途或含义。 async/sync 差异对速度完全没有影响。如果你使用 async 进入主线程,你会在它空闲时立即进入,所以你说 sync 什么也得不到。

此外,如果您已经在 async 后台线程中进入回调,那么任何可以造成的损害都已经造成;你的时间现在不准确,除非你口袋里正好有一台时间机器,否则你绝对无能为力。

根据@matt 关于回调内部调用的建议,我根据 Timer.scheduledTimer 更改了方法。

func record () {
    metronome.restart()
    Timer.scheduledTimer(withTimeInterval: self.barLength, repeats: false) { _ in
        self.startRecording()
        print("Timer fired!")
    }
}

recordhandler 启动 AKMetronome,选择使用 .restart 以便每次请求都从头开始。

A 属性 .barLength 保存 the desired countdown 的计算长度值。调用的 .startRecording 方法是处理 AKRecorder .record 调用的处理程序。

未来 reader,请记住 Timer 并不意味着根据 (Accuracy of NSTimer) 是准确的,但是 不幸的是,这是迄今为止我测试过的最好的方法。