Solution for Ch26 Silver/Gold Challenge in Xcode 9.3

import Cocoa

class ViewController: NSViewController {
  @IBOutlet var textView: NSTextView!
  @IBOutlet weak var speakButton: NSButton!
  @IBOutlet weak var stopButton: NSButton!
  @IBOutlet weak var progressIndicator: NSProgressIndicator!
  
  let speechSynthesizer = NSSpeechSynthesizer()
  var contents: String {
    get { return textView.string }
    set { textView.string = newValue }
  }

  @IBAction func speakButtonClicked(_ sender: NSButton) {
    speakButton.isEnabled = false
    stopButton.isEnabled = true

    let contentsToSpeak = contents.isEmpty ? "The document is empty." : contents
    progressIndicator.maxValue = Double(contentsToSpeak.count)
    progressIndicator.isHidden = false
    speechSynthesizer.startSpeaking(contentsToSpeak)
  }

  @IBAction func stopButtonClicked(_ sender: NSButton) {
    speechSynthesizer.stopSpeaking()
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    speechSynthesizer.delegate = self
    stopButton.isEnabled = false
    progressIndicator.isHidden = true
  }
}

extension ViewController: NSSpeechSynthesizerDelegate {
  func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
    stopButton.isEnabled = false
    speakButton.isEnabled = true
    progressIndicator.isHidden = true
  }

  func speechSynthesizer(_ sender: NSSpeechSynthesizer, willSpeakWord characterRange: NSRange, of string: String) {
    progressIndicator.doubleValue = Double(characterRange.location)
  }
}