Как настроены методы протокола NSSpeechSynthesizerDelegate после настройки? - PullRequest
0 голосов
/ 09 мая 2018

Я работаю над учебником, в котором используется NSSpeechSynthesizer и два его метода протокола NSSpeechSynthesizerDelegate. В моем ViewController я не вызываю явно методы протокола, поэтому мне любопытно, что мне нужно исследовать, чтобы понять, как эти методы вызываются во время выполнения? Методы делегатов работают, как и ожидалось, но мне интересно, как их вызывают, что делает это возможным?

import Cocoa



class MainWindowController: NSWindowController, NSSpeechSynthesizerDelegate, NSWindowDelegate {
    //Now MainWindowController is more powerful by having its own KITT being able to delegate powerful functionality and do less work.  The delegate will do all the heavy lifting and return the results to MainWindowController instances.
    // MARK: - Properties
    @IBOutlet weak var textField: NSTextField!
    @IBOutlet weak var speakButton: NSButton!
    @IBOutlet weak var stopButton: NSButton!
    let speechSynth = NSSpeechSynthesizer.init(voice: NSSpeechSynthesizer.VoiceName.init(rawValue: "com.apple.speech.synthesis.voice.Victoria"))

    var isSpeaking: Bool = false {
        didSet {
            updateButtons()
        }
    }
    // MARK: - Overriden Properties
    override var windowNibName: NSNib.Name? {
        return NSNib.Name("MainWindowController")
    }
    // MARK: - Overidden Methods
    override func windowDidLoad() {
        super.windowDidLoad()
        updateButtons()
        speechSynth?.delegate = self
    }

    // MARK: - UI methods
    @IBAction func speakIt(sender: NSButton) {
        //Get tuype-in text as a string
        let string = textField.stringValue
        if string.isEmpty {
            print("string from \(textField) is empty")
        } else {
            speechSynth?.startSpeaking(string)
            isSpeaking = true
        }
    }

    @IBAction func stopIt(sender: NSButton) {
        speechSynth?.stopSpeaking()
    }

    func updateButtons(){
        if isSpeaking {
            speakButton.isEnabled = false
            stopButton.isEnabled = true
        } else {
            speakButton.isEnabled = true
            stopButton.isEnabled = false
        }
    }

    // MARK: - NSSpeechSynthesizerDelegate Methods
    //this functionality is considered more powerful and is made possible due to the speechSynthesizer.delegate = self
    //the delegate is doing the work and reporting that completed work to the MainWindowController instance
    //so kinda like the delegate is providing the signature and its up to us as the developers based on what we do with those parameters inside the function in order  for us to add our own creativity.
    func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
        //by setting this variable to FALSE, it will fire off the didSet computed property which this variable has both storage and behavior.
        isSpeaking = false
    }

    // MARK: - NSWindowDelegate Methods
    func windowShouldClose(_ sender: NSWindow) -> Bool {
        return !isSpeaking
    }
}

1 Ответ

0 голосов
/ 09 мая 2018

Ваш метод windowDidLoad содержит следующую строку:

    speechSynth?.delegate = self

Это означает, что объект синтезатора речи имеет ссылку на ваш MainWindowController, поэтому объект синтезатора речи может отправлять сообщения на ваш MainWindowController.

Упрощенная реализация внутри NSSpeechSynthesizer может выглядеть примерно так в Swift:

class NSSpeechSynthesizer: NSSoundDelegate {

    weak var delegate: NSSpeechSynthesizerDelegate?

    func startSpeaking(_ string: String) {
        guard
            let audioData = audioData(for: string),
            let sound = NSSound(data: audioData)
            else { return }
        sound.delegate = self
        sound.play()
    }

    // Part of NSSoundDelegate
    func sound(_ sound: NSSound, didFinishPlaying finished: Bool) {
        // The first ? means Swift only sends the message if
        // delegate is not nil.
        // The second ? means Swift only sends the message if delegate
        // implements speechSynthesizer(_:didFinishSpeaking:).
        delegate?.speechSynthesizer?(self, didFinishSpeaking: finished)
    }

}

Но на самом деле это реализовано в Objective-C, где вам нужно быть более подробным о проверке,делегат обрабатывает сообщение:

- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finished {
    if ([delegate respondsToSelector:@selector(speechSynthesizer:didFinishSpeaking:)]) {
        [delegate speechSynthesizer:self didFinishSpeaking:finished];
    }
}
...