Reputation: 103
When I call the startSpeaking(String) method on a NSSpeechSynthesizer instance, with a delegate set, speaking occurs but the following delegate methods never fire:
speechSynthesizer(_ sender: NSSpeechSynthesizer,
willSpeakWord characterRange: NSRange,
of string: String)
func speechSynthesizer(_ sender: NSSpeechSynthesizer,
didFinishSpeaking finishedSpeaking: Bool)
Why? I'm using Swift 4; XCode 9.1; MacOS 10.13.1
Steps to Reproduce:
Compile and run the following:
import AppKit
class SynthDelegate: NSObject, NSSpeechSynthesizerDelegate {
var str = ""
func speechSynthesizer(_ sender: NSSpeechSynthesizer, willSpeakWord characterRange: NSRange, of string: String) {
str = "spoke a word"
}
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
str = "finished speaking"
}
}
let mySpeaker = NSSpeechSynthesizer()
let myDelegate = SynthDelegate()
mySpeaker.delegate = myDelegate
mySpeaker.startSpeaking("test string to read aloud")
sleep(5) // keep alive while speaking
print(myDelegate.str)
Expected Results:
"finished speaking"
Actual Results:
""
Building on OOPers excellent answer, the following WORKS in a new test project:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let mySpeaker = NSSpeechSynthesizer()
let myDelegate = SynthDelegate()
mySpeaker.delegate = myDelegate
mySpeaker.startSpeaking("test string to read aloud")
Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) {_ in
print(myDelegate.str)
}
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
class SynthDelegate: NSObject, NSSpeechSynthesizerDelegate {
var str = ""
func speechSynthesizer(_ sender: NSSpeechSynthesizer, willSpeakWord characterRange: NSRange, of string: String) {
str = "spoke a word"
print(str)
}
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
str = "finished speaking"
print(str)
}
}
Upvotes: 0
Views: 597
Reputation: 47886
Are you testing your code in the Playground? Anyway, you should never call sleep()
in your apps including Playground code.
It prevents many activities needed to make frameworks work such as calling delegate methods. You can use Timer
when you need to execute some code after a delay.
Testable in the Playground:
import AppKit
class SynthDelegate: NSObject, NSSpeechSynthesizerDelegate {
var str = ""
func speechSynthesizer(_ sender: NSSpeechSynthesizer, willSpeakWord characterRange: NSRange, of string: String) {
str = "spoke a word"
print(str)
}
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
str = "finished speaking"
print(str)
}
}
let mySpeaker = NSSpeechSynthesizer()
let myDelegate = SynthDelegate()
mySpeaker.delegate = myDelegate
mySpeaker.startSpeaking("test string to read aloud")
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) {_ in
print(myDelegate.str)
PlaygroundPage.current.finishExecution()
}
Upvotes: 2