Is textField content empty?

#1

In the code on p. 71 which handles the typed in temperature, it starts with the “if let text=textField.text”. From the earlier Swift chapter on Optionals, this code looks like the “optional binding”. Thus, my main question is why is the check for text not being empty needed? I thought if the “if let” worked, this would indicate non-empty text and be the “true” that the if statement needed to continue. Or is the textField variable not really an Optional? I guess I wouldn’t be surprised that it is not since it was not explicitly declared as such in the IBAction func. Thanks for any clarification.

Update: Hmmm, possible indication of assigning text being strong enough is suggested near the bottom of p. 74, where the same code piece is described in its following paragraph with “First you check whether the text field has some text”. So still, do we need the “!isEmpty”?

#2

That’s easy enough to test:

[code]var text: String? = “”

if let x = text {
print(“text is non-nil”)
}

–output:–
text is non-nil[/code]

Also:

  1. A blank string does not evaluate to false (like, say, in python, perl, or ruby):

  2. In any case, a true value is not needed to make the if branch of an if-let statement execute:

[code]let someVal: Bool? = false

if let x = someVal {
print(x)
print(“if branch executed even though x = false”)
}
else {
print(“Else clause”)
}

–output:–
false
if branch executed even though x = false[/code]

All that’s needed for the if branch to execute is for the optional not to be nil. An if-let is not used to test boolean conditions, rather it’s used to check whether an optional is nil; if so, unwrap the optional and assign the value to a variable, else do something else.

#3

So then it sounds like the “isEmpty” is NOT needed, correct?

#4

I’m going to try again because now it seems to me that you were asking about something else. Look at the following example:

import UIKit

let textField: UITextField = UITextField()
textField.text = ""

if let text = textField.text {
    print("if branch")
}
else {
    print("else branch")
}

--output:--
if branch

Now look what happens when you add a where clause:

[code]import UIKit

let textField: UITextField = UITextField()
textField.text = “”

if let text = textField.text where !text.isEmpty {
print(“if branch”)
}
else {
print(“else branch”)
}

–output:–
else branch
[/code]

Clearly, the where clause is relevant. It’s apparent to me that the where clause creates a compound conditional. In this case, the condition is: If text is non-nil AND text is not a blank String, then execute the if branch; else execute the else branch. As with all AND conditionals, both sides have to be true for the if branch to execute. So maybe it’s better to characterize an if-let statement without a where clause as a statement that tests the conditional: someOptional != nil. If yes, then unwrap and assign the value to the if-let variable before executing the if branch.

As an exercise, you can assign nil or a non-blank string to textField.text and examine the output; you can also change the where clause to something unrelated to the text and examine the output.

#5

7 (I hope that’s a polite enough nickname),

 OK, I think I see what's going on. The "text" field of the textField variable/textfield is an Optional. So in an if-let, an assignment using textField.text is true if the label had gotten assigned some text, and I guess no or empty text, or "null" (not "nil") is allowed too. Thus, an isEmpty test is needed to see whether there is any usable text. In your examples, you always assigned something ( or null/empty) to your variable, so the if-let condition was true. Adding the isEmpty check with the "where" allows us to intelligently handle the actual text. So that's why the p. 71 code needs the isEmpty check. My p. 74 code question was "Dude, where's my isEmpty check?". But now I see that we get that in the conversion of the text to a number, where " , value=Double(text)" added to the if-let condition effects the isEmpty check on text. If text was assigned, but empty, the Optional "value" is nil because Double can't convert "no text" to a number and assign "value", so the if-let doesn't trigger. I'm still not 100% clear on if/how we get nil from the textfield content (e.g., does backspacing to remove all text result in nil, or empty?), and your suggested examples would probably clear that up, but I think I can see how to handle text from a textfield clearly enough to handle what I might want to do outside of these examples.

 Also, as I go through these chapters/examples, I'm impressed that you take the time to provide such rich explanations and examples. They really help. Thanks.
#6

7 is good. Nice and brief. :slight_smile:

I don’t know if that is a good way to think about it. In C/C++/Java/Perl/etc. you can write:

if (x = someVal) { ... } else { ... }

And if someVal evaluates to true, then the if branch executes. But an if-let statement:

if let x = someVal { ... } else { ... }

is equivalent to (according to my current mental model) :

if someVal != nil { let x = someVal! ... } else { ... }
A where clause, like isEmpty(), adds another conditional:

[code]if someVal != nil {
let x = someVal!

if x.isEmpty() {
    ...

}
}
else {

}
[/code]
Therefore, there really is no assignment statement here:

if let x = someVal { ....

That assignment statement syntax doesn’t do what it does in C/C++/Java/Perl. In fact, in Swift (as well as in Ruby/Python) it’s illegal to use an assignment statement as a conditional:

[code]
var x: Bool

if x = true {
print(“Hello”)
}

–output:–
error: use of ‘=’ in a boolean context[/code]

Because of all the confusion an if-let statement engenders in beginners, I don’t even think a beginning book should introduce the if-let statement until after using the long version many times first.

Let’s try it out:

[code]import UIKit

let textField = UITextField()

if let text = textField.text {
print(“not nil”) //=> not nil
}
else {
print(“nil”)
}

textField.text = nil

if let text = textField.text {
print(“not nil”) //=> not nil
}
else {
print(“nil”)
}[/code]

So textField.text can never equal nil! That means a UITextField must be defined something like this:

class MyTextField {
    
    var text: String? = "" {
        didSet {
            if text == nil {
                text = ""
            }
        }
    }
}

let myTextField = MyTextField()

if let text = myTextField.text {
    print("not nil")  //=> not nil
}
else {
    print("nil")
}

myTextField.text = nil

if let text = myTextField.text {
    print("not nil")  //=> not nil
}
else {
    print("nil")
}

So, why was the text property declared as an optional type, i.e. String? It wasn’t originally! See here:

stackoverflow.com/questions/3262 … in-swift-2

You’re welcome!

#7

Hi there,

Yes thanks 7 for your time and explanations, very useful !

One question then for me : why is there a question-mark in this code :

Is it because of the “.” that comes after, we put a “?” in case there is no “.” in our textField ?
Or is it because textField.text can be nil ? But then I thought the default value for a String was “” so it’s never nil, is it ?

#8

[quote]Why is there a question-mark in this code :

Or is it because textField.text can be nil ?
But then I thought the default value for a String was “” so it’s never nil, is it ?[/quote]
Well, the text property can be nil for an instant; then it gets reassigned a blank String. But that’s irrelevant: the type of the variable is an optional type, and there is only one way to extract the value from an optional type–you must unwrap it. There are several ways to unwrap an optional, for instance with an if-let, or with optional chaining, as in the code snippet you posted. For details about optional chaining, see here:

developer.apple.com/library/ios … CH21-ID245

#9

OK, good to know, thanks ! I should spend more time on the Apple Library…