Tenant66
Tenant66

Reputation: 121

AVSpeechSynthesizerDelegate implementation in SwiftUI

Can anyone share how we can implement AVSpeechSynthesizerDelegate in SwiftUI. how we can listen to delegate callbacks methods in SwiftUI app.

Thanks

Upvotes: 2

Views: 788

Answers (1)

Neil Smith
Neil Smith

Reputation: 1061

One solution would be to define a class which conforms to ObservableObject. The idea would be to use an @Published property to enable SwiftUI to make updates to your UI. Here's an example of a simple way to keep track of the state of an AVSpeechSynthesizer (I'm unsure of your actual use case):

final class Speaker: NSObject, ObservableObject {
    
    @Published var state: State = .inactive
    
    enum State: String {
        case inactive, speaking, paused
    }

    override init() {
        super.init()
        synth.delegate = self
    }
    
    func speak(words: String) {
        synth.speak(.init(string: words))
    }
    
    private let synth: AVSpeechSynthesizer = .init()
    
}

Then, make this class conform to AVSpeechSynthesizerDelegate like so:

extension Speaker: AVSpeechSynthesizerDelegate {
    
    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
        self.state = .speaking
    }
    
    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didPause utterance: AVSpeechUtterance) {
        self.state = .paused
    }
    
    func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
        self.state = .inactive
    }
    
    // etc...
    
}

Here, I've simply used the delegate callbacks to update a single @Published property, but you could update however you like here depending on your use case. The main point to bear in mind with ObservableObjects is using the @Published property wrapper for any properties you wish to drive UI updates upon a change in value. Here's an example view:

struct MyView: View {
    
    @ObservedObject var speaker: Speaker
    
    var body: some View {
        // 1
        Text("State = \(speaker.state.rawValue)")
            .onReceive(speaker.$state) { state in
                // 2
            }
    }
}

Note how there's two ways to use @Published properties in SwiftUI Views. 1: Simply read the value. SwiftUI will update your view upon a value change. 2: Access the @Published property's publisher with the $ prefix. Using Views onReceive method, you can execute code whenever the publisher emits a value.

Upvotes: 7

Related Questions