我正在尝试让iOS文本到语音合成器“说”一个短语列表,这些短语之间有一个可变延迟。例如,我可能想要它说“你好”,然后等待5秒,然后“有人吗?”,然后等待10秒,然后说“你好?”等等。
我在下面做了一个简单的例子来说明我想要做的事情。我知道语音合成器正在讲话,其他话语被添加到队列中并按接收顺序说出来。
我已经尝试了很多方法来实现循环中的这种延迟。使用print语句测试延迟确认它们正在工作,但它们似乎干扰了第一个短语的文本语言功能,但在说完其余内容之前一直等待for循环。我认为任何这些类型的延迟都会起作用,因为我认为语音合成器是事件驱动的。
我很感激一些帮助,或者至少能够了解它为什么不起作用。谢谢!
以下是示例代码:iPhone 6模拟器,Xcode 7.3
import UIKit
import AVFoundation
class ViewController: UIViewController {
let speechSynthesizer = AVSpeechSynthesizer()
var phraseArray: [String] = ["One", "Two", "Three", "Four", "Five", "Six", "Seven"]
override func viewDidLoad() {
super.viewDidLoad()
for phrase in phraseArray{
let speechUtterance = AVSpeechUtterance(string: phrase)
speechSynthesizer.speakUtterance(speechUtterance)
//"delay()" goes here. It needs to be a variable length delay.
}
}
}
以下是我尝试过的一些延迟方法:
将类设置为语音合成器的委托,并运行while循环,直到合成器完成。
基于时间的延迟:referenceDate = NSDate() while(NSDate().timeIntervalSinceDate(referenceDate) < 0.5) {}
我尝试过堆栈中的“延迟”解决方案,如下所示:Swift delay in loop
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
的Sleep()
答案 0 :(得分:4)
这样的事情怎么样:
import UIKit
import AVFoundation
func delay(_ delay:Double, closure:@escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
class ViewController: UIViewController {
let speechSynthesizer = AVSpeechSynthesizer()
override func viewDidLoad() {
super.viewDidLoad()
speak([("Hello", 5.0), ("Is there anyone there?", 10.0), ("Hello?", 0.0)])
}
func speak(_ phrases: [(phrase: String, wait: Double)]) {
if let (phrase, wait) = phrases.first {
let speechUtterance = AVSpeechUtterance(string: phrase)
speechSynthesizer.speak(speechUtterance)
let rest = Array(phrases.dropFirst())
if !rest.isEmpty {
delay(wait) {
self.speak(rest)
}
}
}
}
}
注意:
speak
。元组对包含要说出的短语和在说出下一个短语之前等待的延迟。speak
获取数组中的第一项,说出该短语,并在等待延迟后再次将该数组的其余部分(如果不为空)传递给speak
。delay
由@matt撰写,来自here。由于上次延迟没有任何用处,您可以将其翻转并在延迟后说出第一个短语。
func speak(_ phrases: [(wait: Double, phrase: String)]) {
if let (wait, phrase) = phrases.first {
delay(wait) {
let speechUtterance = AVSpeechUtterance(string: phrase)
self.speechSynthesizer.speak(speechUtterance)
let rest = Array(phrases.dropFirst())
if !rest.isEmpty {
self.speak(rest)
}
}
}
}
你会像这样使用这个:
// Wait 5 seconds before starting...
speak([(5.0, "I'm sorry Dave."), (2.0, "I can't do that.")])