In the section “Binding the text field to the table cell view” you are shown how to bind list of voice names to the text field in the table. I went through the binding process using the dialog box as explained, but the voice names do not show up in the Table view after I built the App.
The only error I am getting is:
2017-11-21 11:38:19.017988-0800 SpeakLineTwo[7582:2983930] Failed to connect (window) outlet from (SpeakLine.AppDelegate) to (NSWindow): missing setter or instance variable
But I have been getting this error all along and, until I attempted the binding, the program worked as expected.
In the binding dialog box there is a field titled Model Key Path and it is profiled with “objectValue.” I am getting an information message for this field that says:
the vValue binding expects to be bound to an object of type nsstring, but objectvalue is of type (mainwindowcontroller) -> () -> ()
Am I suppose to be adding something to this value such as objectValue.voice?
The text does not call for that, but in searching the web I have found many examples of this.
Any suggestions?
Here is the code for my MainWindowController.swift file:
// MainWindowController.swift
// SpeakLine
//
import Cocoa
class MainWindowController: NSWindowController, NSSpeechSynthesizerDelegate, NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate {
@IBOutlet weak var textField: NSTextField!
@IBOutlet weak var speakButton: NSButton!
@IBOutlet weak var stopButton: NSButton!
@IBOutlet weak var tableView: NSTableView!
let speechSynth = NSSpeechSynthesizer()
let voices = NSSpeechSynthesizer.availableVoices()
var isStarted: Bool = false {
didSet {
updateButtons()
}
}
override var windowNibName: String {
return "MainWindowController"
}
override func windowDidLoad() {
super.windowDidLoad()
updateButtons()
speechSynth.delegate = self
NSSpeechSynthesizer.availableVoices()"
// statement above
for voice in voices {
print(voiceNameForIdentifier(identifier: voice)!)
}
}
// MARK: - Action Methods
@IBAction func speakIt(sender: NSButton) {
//Get typed-in text as a string
let string = textField.stringValue
if string.isEmpty {
print("string from \(textField) is empty")
} else {
speechSynth.startSpeaking(string)
isStarted = true
}
}
@IBAction func stopIt(sender: NSButton) {
speechSynth.stopSpeaking()
}
func updateButtons() {
if isStarted {
speakButton.isEnabled = false
stopButton.isEnabled = true
} else {
stopButton.isEnabled = false
speakButton.isEnabled = true
}
}
func voiceNameForIdentifier(identifier: String) -> String? {
let attributes = NSSpeechSynthesizer.attributes(forVoice: identifier)
return attributes[NSVoiceName] as? String
}
// MARK: NSSpeechSynthesizerDelegate
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
isStarted = false
print("The speechSynthesizer has finished speaking.")
print("finishedSpeaking = \(finishedSpeaking)\n")
}
// MARK: NSWindowDelegate
func windowShouldClose(_ sender: Any) -> Bool {
print("The close window button has been pressed.")
print("isStarted variable is \(isStarted)\n")
return !isStarted
}
//MARK: - NSTableViewDataSource
func numberOfRows(in tableView: NSTableView) -> Int {
return voices.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> AnyObject? {
let voice = voices[row]
let voiceName = voiceNameForIdentifier( identifier: voice)
return voiceName as AnyObject?
}
//MARK: - NSTableViewDelegate
func tableViewSelectionDidChange(_ notification: Notification) {
let row = tableView.selectedRow
if row == -1 {
speechSynth.setVoice(nil)
return
}
let voice = voices[row]
speechSynth.setVoice(voice)
}
}