Swift iOS文字转语音无法在循环中使用“延迟”

ben*_*ish 4 text-to-speech delay ios swift

我正在尝试让iOS文本语音合成器“说”短语列表,这些短语之间存在可变的延迟。例如,我可能要说“你好”,然后等待5秒钟,然后“有人在吗?”,然后等待10秒钟,然后说“你好?” ...等等。

我在下面做了一个简单的例子,说明了我要做什么。我知道语音合成器正在讲话,其他语音被添加到队列中并按照接收顺序进行讲话。

我尝试了许多方法来实现循环中的此延迟。使用打印语句测试延迟可以确认它们是否有效,但是它们似乎干扰了text-speach-function功能,该功能说的是第一个短语,但要等到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.

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  3. 我已经尝试过从堆栈中“延迟”解决方案,就像这样: 循环中的快速延迟

    func delay(delay:Double, closure:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure) }

  4. 睡觉()

vac*_*ama 5

这样的事情怎么样:

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)
                }
            }
        }
    }    
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 元组数组传递给speak。一个元组对包含一个要说的短语和一个等待说下一个短语的延迟。
  • speakspeak在等待延迟之后,从数组中获取第一项,说出短语,然后将数组的其余部分(如果不为空)传递给其他人。
  • delay是@matt编写的,来自这里

由于最后一个延迟没有任何用处,因此您可以将其转过来,并在延迟后说出第一个短语。

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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以这样使用:

// Wait 5 seconds before starting...
speak([(5.0, "I'm sorry Dave."), (2.0, "I can't do that.")])
Run Code Online (Sandbox Code Playgroud)