AVSpeechSynthesizer isSpeaking не работает в Swift

Итак, после обновления до Xcode 12.0.1 AVSpeechSynthesizer теперь работает на симуляторе (у меня он некоторое время не работал). Теперь переменная isSpeaking всегда имеет значение false независимо от того, говорит ли синтезатор. Я хотел бы вызвать изменение моего представления в зависимости от того, говорит ли синтезатор. Простая версия ниже, есть идеи?

import SwiftUI
import AVFoundation

struct ContentView: View {

var synthesizer = AVSpeechSynthesizer()
var utterance = AVSpeechUtterance(string: "Hello World")

var body: some View {
    VStack {
        Text(synthesizer.isSpeaking ? "Speaking" : "Not Speaking")
        Button(action: {synthesizer.speak(utterance)}) {
            Text("Speak To Me")
        }
    }
}
}

person Mike R    schedule 28.09.2020    source источник


Ответы (1)


В вашем случае он просто не обновляется, потому что synthesiser.isSpeaking не наблюдается для SwiftUI. Вы должны использовать класс модели представления и делегировать обратные вызовы для обработки изменений этого состояния.

Вот начальная демонстрация (вы можете самостоятельно добавить действия остановки/паузы/продолжения)

class SpeachViewModel: NSObject, ObservableObject, AVSpeechSynthesizerDelegate {
    @Published var isSpeaking = false

    private var synthesizer = AVSpeechSynthesizer()
    override init() {
        super.init()
        synthesizer.delegate = self
    }

    deinit {
        synthesizer.delegate = nil
    }

    func speak(_ utterance: AVSpeechUtterance) {
        self.synthesizer.speak(utterance)
    }

    // MARK: AVSpeechSynthesizerDelegate
    internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
        self.isSpeaking = true
    }

    internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
        self.isSpeaking = false
    }

    internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didPause utterance: AVSpeechUtterance) {
        self.isSpeaking = false
    }

    internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
        self.isSpeaking = false
    }

    internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didContinue utterance: AVSpeechUtterance) {
        self.isSpeaking = true
    }
}

struct ContentView: View {

    @ObservedObject var vm = SpeachViewModel()
    var utterance = AVSpeechUtterance(string: "Hello World")

    var body: some View {
        VStack {
            Text(vm.isSpeaking ? "Speaking" : "Not Speaking")
            Button(action: {vm.speak(utterance)}) {
                Text("Speak To Me")
            }
        }
    }
}
person Asperi    schedule 29.09.2020
comment
Вот и получилось, большое спасибо! Я был близок, настроил класс делегата, но изо всех сил пытался понять внутренние функции, описанные выше. Ваше здоровье! - person Mike R; 01.10.2020
comment
Добро пожаловать на СО. Что делать, когда кто-то отвечает на мой вопрос? - person Asperi; 01.10.2020