Assign value with optional question mark - ios

I'm currently learning Swift from basics. Now I'm on optionals and I'm trying to understand this case:
var text: String? = nil
text? = "some text"
What happens exactly if we assign value with question mark? I don't understand why the value of text is nil. Can you explain me what is the difference between assigning text = "some text" and text? = "some text"?

You're right to be surprised. text? = means "If text is nil don't perform the assignment."
You've stumbled across a highly obscure language feature. See https://ericasadun.com/2017/01/25/pretty-much-every-way-to-assign-optionals/
(As she rightly says, you can count on the fingers of zero hands the number of times you'll ever actually talk like this, because who would ever want to assign a value only just in case the lvalue is already non-nil?)
NOTE I prefer to look at this as a zero-length variant of optional chaining. It is extremely useful to be able to say e.g.
self.navigationController?.hidesBarsOnTap = true
meaning, if self.navigationController is nil, fuhgeddaboudit. Well, your use case is sort of a variant of that, with nothing after the question mark. Most people are unaware that if the last object in the chain is an Optional, the chain can end in a question mark. The expressions in f are all legal:
class C {
struct T {
var text : String?
}
var t : T?
func f() {
self.t?.text = "howdy"
self.t? = T()
self.t?.text? = "howdy"
}
}
But only the first one, self.t?.text =, is common to say in real life.

Related

How can I convert a string in a textfield to an Int in Swift?

I tried for a long time to turn the text into an Int but it did not work. I tried it like this:
(AnzahlString is a textfield)
var AnzahlAInt = 0
if let AnzahlAString = AnzahlString.text {
let AnzahlAInt = Int(AnzahlAString)
}
But then I always get the error:
Value of optional type 'Int?' must be unwrapped to a value of type 'Int'
Then I added a ! at the end of Int(AnzahlAString)! so I don't get a error, but now when I press on the button, the app crashes. It was predictable, but how can I change this now to an Int without the !?
At first glance, it looks like you have two things to check for:
is AnzahlString.text present, and
does it represent an Int
The first check is in fact not necessary, since .text will never return nil, even though it's marked as Optional. This means you can safely force-unwrap it.
The second check is easily done by using the ?? operator:
let AnzahlAInt = Int(AnzahlString.text!) ?? 0
PS, just as a stylistic hint: variable names in Swift ususally start with a lowercase letter, names starting with capital letters are used for types.
PPS: your code as written shadows AnzahlAInt - the value of your var is never changed.
The reason why the resulting Int is optional, is that parsing might or might not succeed. For example, if you try to parse the string "Fluffy Bunnies" into an Int, there is no reasonable Int that can be returned, therefore the result of parsing that string will be nil.
Furthermore, if you force the parser by using !, you're telling Swift that you know for sure that the string you pass will always result in a valid Int, and when it doesn't, the app crashes.
You need to handle the situation in which the parse result is nil. For example:
if let AnzahlAIntResult = Int(AnzahlAString) {
// We only get here if the parse was successful and we have an Int.
// AnzahlAIntResult is now an Int, so it can be assigned to AnzahlAInt.
AnzahlAInt = AnzahlAIntResult
}
You did a good job so far but missed out one thing.
This line tries to convert the String into an Int. However this can fail, since your String can be something like this "dfhuse".
let AnzahlAInt = Int(AnzahlAString)
This is why the result of Int(AnzahlAString) is an Optional (Int?). To use it as an real Int, you have to unwrap it.
First solution is the !, however, every time this does fail your app crashes. Not a good Idea to use so.
The best solution would be Optional Binding, as you already used to get the text of your text field.
if let AnzahlAString = AnzahlString.text {
if let safeInt = Int(AnzahlAString) {
// You can use safeInt as a real Int
} else {
print("Converting your String to an Int failed badly!")
}
}
Hope this helps you. Feel free to ask again if something is unclear.
For unwrapping you can also use guard like this
Simple and easy
guard let AnzahlAInt = Int(AnzahlString.text!) else {
return
}
print(AnzahlAInt)

Quiz: How to integrate an alternative/a similar answer as declared correct in a UITextField

Dear StackOverflowers,
I did a search but couldn't find anything in here or Google. As a total beginner I hope not to beeing punished with these minus ratings :)
Imagine a little quiz. At App Start there's a randomly generated String from a Dictionary telling the correct answer. Let's say it's this Dictionary:
let dictionary: Dictionary = [0: "One", 1: "Two", 2: "Three", 3: "Four", 4: "Five"]
And now I'm generating a random String from it:
var randomNumber: Int = 0
var randomString: String = ""
randomNumber = Int(arc4random_uniform(UInt32(dictionary.count)))
randomString = Array(dictionary.values)[randomNumber]
Now there's a Question and the code knows that the correct answer is randomString.
I have a TextField for the user to guess the answer. Type your answer, click on „guess“ and then there's a result displayed in a label, generated with...
if textField.text == randomString {
resultLabel.text = "Correct!"
} else {
resultLabel.text = "Wrong!" }
Question: Is it possible to make partially correct answers also being displayed as „Correct!“? Let's say the user types „4“ instead of „Four“. Or in another case the correct answer would be „Harry and the Turtle Tubes“ and the user just types „Harry and the Turtles“ (shorter) or „harry and the turtle tubes“ (all words written in lower case).
I'm thankful for all your hints and code snippets.
Have a great day
Patrick
What you want to search for is "fuzzy string matching". You can read about it on Wikipedia.
There are a number of Swift libraries that exist that implement this. You will need to find one that best suits your needs.
Good luck!

How can i use the implicitly unwrapped optional in swift programming? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
iam very new to the swift programming.i have a wrote a basic program in swift. i confused about the unwrapped optional concept and in this program i have already declared celsius and fahrenheit as unwrapped optional by default. my question is
Why do we need to unwrap again as celsius.text!
can you please provide solution for this...Thank you
PROGRAM CODE
You have non-optional UITextField, but its property text is String? type, you must unwrap it like:
if let text = celsius.text {
print(text)
}
You need to include the defintion of celsius and fahrenheit.
I'm guessing that they are UITextField or UITextView objects.
Those two view types have properties text which are declared as optionals. So you have optional reference to a text field that contains a reference to an optional string.
So even though you declared celsius as celsius: UITextField!, the text property is also an optional, so you need to say
celsius.text? = ""
Note that declaring a variable as an implicitly unwrapped optional is dangerous, because any time you reference that variable, the compiler will try to unwrap it for you (It says "This is an Optional, but trust me, it will never be nil.) This is like having an elevator where you push the button and the door opens, whether the car is there or not, and you step through without looking. If the car is there, great. If not, you fall to your death. You better be sure the elevator will always be there!
Outlets are one case where it's common to use implicitly declared optionals, because the outlets should be hooked up in IB (Interface Builder). If an outlet is not hooked up, you want to know about it right away, so crashing is reasonable.
Think of the ! operator as the "crash if nil" operator, and avoid it until you really understand optionals. (With the exception of outlets, as discussed above.)
You can do it like that. Try to avoid using force unwrapping (! operator) on optionals.
func conversion() {
if ( celsius.text == "" ) {
if let fahrenheitText = fahrenheit.text, let fahrenheitValue = Double(fahrenheitText) {
let celsiusValue = fahrenheitValue - 32 * 5 / 9 //or whatever is the formula..
celsius.text = "\(celsiusValue)"
fahrenheit.text = ""
}
} else if ( fahrenheit.text == "" ) {
if let celsiusText = celsius.text, let celsiusValue = Double(celsiusText) {
let fahrenheitValue = 9 * celsiusValue / 5 + 32 //or whatever is the formula..
fahrenheit.text = "\(fahrenheitValue)"
celsius.text = ""
}
}
}

SWIFT: var someVariable:int = textfield.text.toInt() x textfield2.text.toInt() and force unwrap

First post here so please be gentle. Am fairly new to coding and am trying to get my head around SWIFT and its optionals. Would really appreciate some advice from the pros!
I am writing a simple app whereby textfields are entered by the user and then some multiplication occurs in app before spitting out an answer into another textfield on the press of a button: "calculateTM".
I am having some trouble with the calculation itself and perhaps it's because I am trying to do too much on one line - take the textfield entry, convert to integer, multiply with another textfield entry converted to an integer, essentially what I wrote in the title:
var someVariable: Int = textfield.text.toInt() * textfield2.text.toInt()
The problem is, Xcode is wanting my to force unwrap and add an ! to the end of both toInt(). This is fine, except of course when the user doesn't enter anything into the boxes and presses calculate, at which point the nil value causes the program to crash, e.g.:
var someVariable: Int = textfield.text.toInt() x textfield2.text.toInt()
var someVariable2: Int = textfield3.text.toInt() x textfield4.text.toInt()
where the user doesn't enter anything into textfield3 or 4
Following this simple arithmetic, the code updates the labels (which are textfields) as such:
label1.text = String(someVariable)
label2.text = String(someVariable2)
So this final conversion back to a string might also create some issues as to how the optionals are treated in the first part of the code.
Apologies for the long-winded explanation, and I hope I've been clear enough, but I imagine I am missing something really basic with the first part of the code. I have tried using the optional ? and also the nil-coalescing operator (to set to 0 in case of nil) but can't get it to work. Please help?
Many thanks in advance!
Use if let for optional binding:
if let var1 = textField.text?.toInt(),
let var2 = textField2.text?.toInt() {
someVariable = var1 * var2 // or directly label1.text = String(var1 * var2)
}
The method toInt() actually returns an optional type 'Int?' that can be nil or integer value, so you need to check if the String->Int cast successful returns an Int or a nil.
For the most basic way:
var intValue: Int? = text.toInt()
if intValue != nil {
// operations using intValue!
}
In swift, you can try:
if let intValue = text.toInt() {
// operations
}

Why does String implicitly become String! in Swift

I received a compilation error from Xcode yesterday, saying
Binary operator '&&' cannot be applied to two Bool operands [1]
on
if text != nil && presentingViewController != nil {
...
}
text is defined earlier as
var text: String = "" {
didSet {
...
}
}
and presentingViewController is from UIViewController, which is the super class.
A friend of mine told me that it was caused by text, which was of String!, and the issue was solved by changing
var text: String
to
var text: String?
However, it still puzzles me why my explicitly defined String becomes String!. Can anyone provide any detail on this implicit conversion?
[1] This compilation error does not make sense, and this question is not a duplicate of another question of the same compilation error.
Your problem is related to what is called "optionals" in swift.
In Objective-C you could have a reference to NSString and it could either be pointing to an NSString instance - or to nil. In swift this is different!
A "regular" String in swift can never be nil. Only an "optional" String can be nil. This is how it would look in swift code:
var myRegularString : String // this can never be nil, can't compare to nil
var myOptionalString : String? // this can be nil (note the ?)
You have a "regular" String. So the compiler complains when you try to compare it to nil.
Optionals are explained here: Swift Programming Language/Basics/Optionals
Your explicitly defined String is not String! is ... String. Simple like that ;-)
String! is an implicitly unwrapped Optional<String>
String? is an Optional<String>
Optional<T> means that it can be a value of type T or Nothing (and nothing can be compared to nil).
Thus when you declare:
var text = ""
you declare an actual String and it cannot be nil. That's why the compiler is complaining: a String cannot be Nothing. Think of it as comparing a String with a CGFloat ... the compiler will complain.
Since String! is an Optional<String> than it can be compared against nil.
The ! simply is you declaring that you are absolutely sure it is not Nothing such that you can use text without unwrapping its actual value.
BTW, do not confuse and empty String (i.e.: "") with Nothing.
var text = "" is an actual String just empty and it is not comparable with Nothing
Hope this helps.
Your friend most certainly didn't solve your problem, he just glossed over it.
You declared an instance variable of type String. text will always be a String. It can never, ever be nil. Asking "text != nil" is pointless because it cannot be nil. It doesn't even compile, because a String, always being nil, cannot even checked for being nil.
Your friend suggested to use String? or String!. That's in your situation total nonsense. You have text which is guaranteed to be always a String. Instead you change it to text which may be a String or nil. This doesn't help you in any way. Yes, now you can ask it whether it is nil. Before, you didn't even have to ask.

Resources