List of voices won't show in Table View

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)
}

}