swift - 设置好后,如何自动调用 NSSpeechSynthesizerDelegate 协议方法?
问题描述
我正在学习使用 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
}
}
解决方案
您的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];
}
}
推荐阅读
- javascript - 从 Fetch 中获取 Json 数据
- python - 将年和周的整数更改为日期时间
- powerbi - 针对 API 请求在 Power Query 中对 distinctList 进行简单 for 循环
- azure - 有没有办法在 Azure 应用服务中记录 http 请求的正文?
- android - 深层链接不适用于 Instragram 故事向上滑动
- python - 安装 NLTK 时出错
- laravel - 在 laravel 中的数据透视表上定义附加关系
- python - 字典列表可以用适当的结果排序
- javascript - 如何在javascript中检查和添加属性到数组对象
- java - 如何复制列表
进入java中的当前数组列表?(通用列表)