AVSpeechSynthesizer error: An AVSpeechUtterance shall not be enqueued twice

AVSpeechSynthesizer error: An AVSpeechUtterance shall not be enqueued twice

我有点卡住了。

这是我的代码:

let speaker = AVSpeechSynthesizer()
var playQueue = [AVSpeechUtterance]() // current queue
var backedQueue = [AVSpeechUtterance]() // queue backup

...

func moveBackward(_ currentUtterance:AVSpeechUtterance) {
    speaker.stopSpeaking(at: .immediate)
    let currentIndex = getCurrentIndexOfText(currentUtterance)
    // out of range check was deleted
    let previousElement = backedQueue[currentIndex-1]
    playQueue.insert(previousElement, at: 0)
    for utterance in playQueue {
        speaker.speak(utterance) // error here
    }
}

根据文档 AVSpeechSynthesizer.stopSpeaking(at:):

Stopping the synthesizer cancels any further speech; in constrast with when the synthesizer is paused, speech cannot be resumed where it left off. Any utterances yet to be spoken are removed from the synthesizer’s queue.

当我在 AVSpeechSynthesizer 队列中插入一个 AVSpeechUtterance 时,我总是得到错误(AVSpeechUtterance 不得入队两次)。但它应该根据文档停止。

停止播放器时,话语肯定会从队列中删除。

但是,在您的 moveBackward 函数中,您在 playQueue[0] 处插入了另一个 AVSpeechUterrance,其完整数组表示玩家队列。

假设停止发生在currentIndex = 2,以下快照证明同一个对象在队列中被注入两次

  • 复制backedQueue[1],即playQueue[1](相同内存地址)的副本。

  • playQueue[0]处插入backedQueue[1] (原playQueue[1]变为新的playQueue[2]

不幸的是,正如系统指示的那样,AVSpeechUtterance 不应入队两次 而这正是您在这里所做的:playQueue 索引 0 和 2 处的对象 具有相同的内存地址.

在索引 0 处插入新对象后的最后一个循环要求语音合成器将所有话语放入其全新队列中...其中两个是相同的。

而不是将 playedQueue 复制到 backedQueue (两者都包含指向其对象的相同内存地址) 或者在两个数组中附加相同的语句, 我建议创建不同的话语实例 如下:

    for i in 1...5 {

        let stringNb = "number " + String(i) + " of the speech synthesizer."
        let utterance = AVSpeechUtterance(string: stringNb)
        playQueue.append(utterance)

        let utteranceBis = AVSpeechUtterance(string: stringNb)
        backedQueue.append(utteranceBis)
    }

遵循这条建议,您应该不会遇到错误 AVSpeechUtterance shall not be enqueued twice.