UIlabel text does not show "optional" word when setting optional text? - ios

I have been using optional a lot.I have declared a string variable as optional
var str: String?
Now i set some value in this variable as str = "hello".Now if i print this optional without unwrapping then it print as
Optional("hello")
But if i set text on the label as self.label.text = str then it just display value as
hello
Please explain why it does not show text as on label
Optional("hello")

The text property of UILabel is optional. UILabel is smart enough to check if the text property's value is set to nil or a non-nil value. If it's not nil, then it shows the properly unwrapped (and now non-optional) value.
Internally, I imagine the drawRect method of UILabel has code along the lines of the following:
if let str = self.text {
// render the non-optional string value in "str"
} else {
// show an empty label
}

I knew I've seen optionals printed in UILabel, UITextView, UITextField. Rmaddy's answer wasn't convincing.
It's very likely that there is an internal if let else so if the optional has a value then it will unwrap it and show. If not then it would show nothing.
However there's a catch!
let optionalString : String? = "Hello World"
label.text = "\(optionalString)" // Optional("Hello World")
label.text = optionalString // Hello World
let nilOptionalString : String?
label.text = "\(nilOptionalString)" // `nil` would be shown on the screen.
label.text = nilOptionalString // no text or anything would be shown on the screen . It would be an empty label.
The reason is that once you do "\(optionalVariable)" then it would go through a string interpolation and once its a String and not String? then the result of the interpolation would be shown!

Related

Force unwrapping (UITextField().text!) Not Crash .But (UILabel().text!) Crash

Check this please i need explain why texField.text! not crash and label.text! crash
And as we know UITextField has property open var text:String? and UILabel have open var text:String?
let texField = UITextField()
texField.text = nil
print(texField.text!) // not crash
let label = UILabel()
label.text = nil
print(label.text!) //crash
From the documentation of UITextField
Declaration
var text: String? { get set }
Discussion
This string is #"" by default.
From the documentation of UILabel
Declaration
var text: String? { get set }
Discussion
This property is nil by default.
Please note the subtle difference
As a general rule of thumb, you should never force-unwrap optional values like this.
You should use if-let or guard or any way provided by swift to handle optionals safely.
If a label has no text, then label.text will return nil.
However, if a text field has no text then textField will return "" (an empty string). That's why it will not crash if you force-unwrap the text property of a text field.
I'm not sure why it designed like this by Apple, but as I wrote above you should handle optionals safely.

How do I assert that a text field is empty?

I have an empty text field on my UI, though it has a placeholder text (whose value is foo) set in the storyboard. In my UI test, I am trying to check that its text value starts out empty, but when I query it's value, it seems to be giving me the placeholder value instead:
func testTextFieldInitiallyEmpty {
let input = XCUIApplication().textFields["My Text Field"]
XCTAssertEqual(input.value as! String, "")
}
as the test fails with this message:
XCTAssertEqual failed: ("foo") is not equal to ("")
Of course, foo is the placeholder value, but it's not the text value of that text field. I would have expected that error message if I had written:
XCTAssertEqual(input.placeholderValue as! String, "")
input is a XCUIElement, which implements XCUIElementAttributes, so I don't see anything else that would do the trick here.
How do I check (assert) that the text field is empty?
Edit
After doing some further research and trying out the suggestions below for using the input's properties of accessibilityValue, label, and title, I have not found any solution that will give me the text field's text value when there is text, and an empty string when only the placeholder is visible.
This seems like either (a) a bug, or (b) a questionable design decision from the test framework to not provide that ability. At a minimum, the documentation for XCUIElementAttributes#value seems inadequate to me, as the only detail is:
The exact type of value varies based on the type of the element.
Still looking for a better solution...
You can compare to the XCUIElementAttributes's placeholderValue variable in addition to checking for a blank string
extension XCUIElement {
func noTextEntered() -> Bool {
return self.value as? String != "" && self.value as? String != placeholderValue
}
}
Then you can run XCAssert(input.noTextEntered(), "Unexpected text entered into field")
Just make sure your placeholder is not something a user would type in. This way you don't have to hardcode placeholder values to check against
Kind of ridiculous that this is actually the case it works and that it needs a workaround.
Anyway, my solution to get the value w/o the placeholder interfering, based on #Jason's answer.
extension XCUIElement {
var valueWithoutPlaceholder: String {
if let v = value as? String, v != placeholderValue {
return v
}
return ""
}
}
Be aware, if the input is actually the placeholder this would break!
Try using accessibilityValue property of input.
func testTextFieldInitiallyEmpty {
let input = XCUIApplication().textFields["My Text Field"]
XCTAssertEqual(input.accessibilityValue, "")
}
If you command+click the property, you can see the following..
/*
Returns a localized string that represents the value of the element, such as the value
of a slider or the text in a text field. Use only when the label of the element
differs from a value. For example: A volume slider has a label of "Volume", but a value of "60%".
default == nil
default on UIKit controls == values for appropriate controls
Setting the property will change the value that is returned to the accessibility client.
*/
public var accessibilityValue: String?

Set label value dynamically in a table cell

hello I am having a very weird problem in my code and I don't know whats actually going on here.
I have label set in my view controller and when I set the value like this
cell.totalTripsLabel.text = "55"
It works.
But If I try to set value from dictionary,
cell.totalTripsLabel.text = self.dict["totalTrips"]! as? String
It doesn't work at all and nothing displays on ViewController.
If I print the value like this
print(self.dict["totalTrips"]!)
It successfully prints the integer value
But If I do this
print(self.dict["totalTrips"]! as? String)
It prints nil
So I figure out by casting a value to string, it prints nil. So question is how I can set value in label which accepts string value
Dictionary result is like this
{
totalTrips = 2;
}
try this
cell.totalTripsLabel.text = String(self.dict["totalTrips"]!)

How can i get the data from Swift based IBOutlet UITextField?

#IBOutlet var firstName:UITextField?
#IBOutlet var lastName:UITextField?
let string = firstName!.text
print(string)
The output is like as below:
Optional("ohh")
How can I get the data without optional text and double quotes?
Your issue is that the text attribute of a UITextField is an Optional - this means it must be unwrapped. To do that, you add a ! to the end, which produces a String instead of a String?.
You can also conditionally unwrap an optional using the syntax if let, so here it would be
if let string = firstName!.text{
print(string) //outputs if text exists
}else{
//text didn't exist
}

UILabel AutoResize Swift

I'm learning Swift, but I Have two "stupid" Problems.
the first, I'd like autosize my UILabel
The second, I have another UIlabel and I want to put name and surname in it's field
I tried with
#IBOutlet weak var title: UILabel!
title.text = currentPerson?.name+""+currentPerson?.surname
But I have this error
Value of optional type 'String?' not unwrapped; did you mean to use
"!" or "?" ?
Generally advised to ask 1 question per post so you get clear responses & don't mix topics, but...
In XCode storyboard "Attributes Inspector" you can change "Autoshrink" from "Fixed Font Size" to minimum font size or scale. Also change "Lines" from default 1 to 0. You'd also need to set some AutoLayout constraints to pin the label to superview or other elements in a way that will allow it to scale. Can't say more w/o seeing storyboard.
By using optional chaining to set the label text you're trying to set the label's .text property to an optional type String? instead of a String. Those aren't equivalent. An optional of type String? might contain a String, or it might be nil. The UILabel expects you to use a String instance, so it's complaining about the mismatch.
One approach is to explicitly check the optional value against nil:
if currentPerson != nil {
title.text = "\(currentPerson.name) \(currentPerson.surname)"
}
else {
title.text = ""
}
Swift's optional binding is similar to the first option, but you create a temporary constant and can reference its properties. If currentPerson is not nil, then the if block executes.
// current convention would be to use "currentPerson" on both sides, which can be confusing. The left side is a temporary constant & the right side is the optional property you've declared somewhere above
if let aPerson = currentPerson {
title.text = "\(aPerson.name) \(aPerson.surname)"
}
else {
title.text = ""
}
Alternatively, as the error message suggests, you could Force Unwrap the optional value to access the name properties:
title.text = currentPerson!.name + " " + currentPerson!.surname
This assumes that currentPerson is never nil. If it is nil, your app will crash here.
Also note you can concatenate using + and " " or with string interpolation.

Resources