Swift iOS Text To Speech无法在循环中使用“延迟”

时间:2016-05-17 22:32:00

标签: ios swift delay text-to-speech

我正在尝试让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.

        }
    }
}

以下是我尝试过的一些延迟方法:

  1. 将类设置为语音合成器的委托,并运行while循环,直到合成器完成。

  2. 基于时间的延迟:referenceDate = NSDate() while(NSDate().timeIntervalSinceDate(referenceDate) < 0.5) {}

  3. 我尝试过堆栈中的“延迟”解决方案,如下所示: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) }

  4. 的Sleep()

1 个答案:

答案 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.")])