在我的命令行应用程序中,DispatchSemaphore 不会等待,尽管初始化为零,通过“等待”递减并通过“信号”递增。我不想使用 RunLoop.main.run()。
import Foundation
import AVFoundation
var synthesizer = AVSpeechSynthesizer()
let sema = DispatchSemaphore(value: 0)
func say(_ line: String) {
let utterance = AVSpeechUtterance(string: line)
synthesizer.speak(utterance)
sema.signal() // increment
}
say("hello")
sema.wait() // decrement
//RunLoop.main.run()
AVSpeechSynthesizer.speak(_:)
记录仅“将您指定的话语[添加]到语音合成器的队列中”;合成器不一定立即开始说话,speak(_:)
调用也不会等到合成器完成说话后再返回。
实际上,
synthesizer.speak(utterance)
会立即返回,这会立即向您的信号量发出信号。如果这是您的全部代码并且您将其作为脚本运行,则省略 RunLoop.main.run()
意味着您的程序也会立即结束,并且合成器永远没有机会说话。
要了解语音事件(例如,当合成器开始和停止说话时),您需要创建一个符合
AVSpeechSynthesizerDelegate
协议的类型,并将该类型的实例设置为合成器的委托。然后您可以根据需要响应事件。
顺便说一句,
DispatchSemaphore
一般不建议用于此类同步目的,因为作为极低级的同步工具,它可能会导致优先级反转(如果使用不当,很容易死锁)。如果您详细说明尝试使用信号量的原因,我们可以就如何最好地替换它提供更有针对性的建议。