Error: Initializer for conditional binding must have Optional type, not 'String.'


#1

Hi this is probably a noob question. I’ve been going through Swift Programming: The Big Nerd Ranch Guide (2nd Edition).

Chapter 26 (Your First Cocoa Application) has us create a desktop application for Mac, called VocalTextEdit.

I followed along but the bottom of page 701 has code that gives me that error.

While I’m a noob, it’s also legitimately confusing that this well-known book directs us to create an app that doesn’t work lol.

I’ll copy-paste my code so far, which follows along with the book, up to that point. The error message is based on the line “if let contents…”

import Cocoa

class ViewController: NSViewController {
    
    let speechSynthesizer = NSSpeechSynthesizer()
    
    
    
    @IBOutlet var textView: NSTextView!
    
   
    
    @IBAction func speakButtonClicked(_ sender: NSButton) {
            if let contents = textView.string {
            speechSynthesizer.startSpeaking(contents)
        } else {
        
            speechSynthesizer.startSpeaking("The document is empty.")
        }
    }
    
    
    @IBAction func stopButtonClicked(_sender: NSButton) {
            print("The stop button was clicked")
    }
    
    
}

#2

What is the error message?


#3

Sorry, the error message is the title of my original post:

“Error: Initializer for conditional binding must have Optional type, not ‘String.’”

The message comes up while underlining the “let” in my line, “if let contents = textView.string…”

I’ve searched online a bit, and the error is saying that the “if let” statement isn’t working, because it’s not seeing the following code as Optional type. (Though I’m not sure what to think of that; it’s obviously supposed to be referring to the textfield possibly having text, and possibly not. Also, I believe my code is exactly the same as in the book. I’d post a screenshot of everything if I saw that option in this forum…)


#4

One of the challenges with following an older textbook is that … tons of Swift’s APIs changed in the Swift 3 transition.

Apple changed the NSTextView API (link below), it’s now not an optional String (Not a String? type, so you can’t use the if let syntax).

You can use it directly:

@IBAction func speakButtonClicked(_ sender: NSButton) {
     speechSynthesizer.startSpeaking(textView.string)
}

Or you can test to see if the String is empty in the TextView.

@IBAction func speakButtonClicked(_ sender: NSButton) {

    if textView.string.isEmpty {
        speechSynthesizer.startSpeaking("Type something for me to say!")
    } else {
        speechSynthesizer.startSpeaking(textView.string)
    }
}

The property comes from the NSText class.


#5

Thanks! Both examples work; I appreciate it.


#6

How about one more noob question. I almost didn’t ask, because it must be a real simple question, but OTOH it really is confusing that the book’s directions are not quite working for the next part: The stop button.

My build still succeeds, but my stop button doesn’t work, and it’s such a small line of code, which I’m typing exactly as the book:

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

Is there an obvious reason for that not to work (i.e. to stop the voice, when it’s talking)?


#7

Did you get it working?

I would take a look at the documentation, there may be another API to call.

AVSpeechSynthesizer API

It looks like something like this line will make it work:

speehSynthesizer.stopSpeakingAtBoundary(.immediate)

#8

You’ve probably figured the problem by now, but…
Unless your copy and paste failed to pick up the very last character, should there be a ‘closing’ curly brace ( -> } <- ) at the end of that line? Of course, it’s possible it’s on the next line down of even below some more code… :grin: