I am begining with swift and iOS and I have crashed against a doubt. Let see, having this particular source code:
if object?.stringValue != nil {
// send it to server
session.stopRunning()
sendQRCodeToApiServer(stringValueObtained: (object?.stringValue)!)
}
I understand that in if object?.stringValue != nil
the ? character means that object var could be nil, so it is an optional. But in the internal line:
sendQRCodeToApiServer(stringValueObtained: (object?.stringValue)!)
The interpreter throws an error if I don't unwrap the object?.stringValue in () and with a exclamation mark (!), that (if I had understood perfect) means that you are sure that the result have a value and it has the type required, I mean, the object.stringValue has a value and IT IS a string.
Well, I understand this perfect, but the compiler says that ? and ! are required, first says that maybe has a value and second that is sure that has a value, ........
I see this syntax incongruent and confusing, can anyone explain me?
Thanks a lot for your time
Optionality / force unwrapping / optional chaining can be very confusing.
As a rule of thumb if you are finding that you have to force unwrap variables 'unexpectedly' then it is absolutely worth revisiting the code to deliberately unwrap variables you wish to access.
Some might say "Every time you use an ! , a baby unicorn dies (horribly)"
In your first line of code, object is an optional
if object?.stringValue != nil {
unless you specifically unwrap object you have to use the ? notation whenever you access it or it's members. Thats why when you access it again later inside the method call to sendQRCodeToApiServer, you have to unwrap it again.
When you unwrap an optional, the name you give to the unwrapped version of the variable works just like any other variable in that scope. Also when you unwrap an optional bear in mind that you are actively reducing the number of ? and ! that appear in your code so you are really making it much more readable and understandable for yourself in 6 months time or the next developer that sees your code (Hey and the unicorns love you).
Let's unwrap specifically the only variable you wish to use (if you had many lines of code that access object members then we could unwrap object - but let's stick with your code example)
if let stringValueObtained = object?.stringValue {
// send it to server
session.stopRunning()
sendQRCodeToApiServer(stringValueObtained: stringValueObtained)
}
Note:
Outside of the scope of the if statement stringValueObtained does not exist
I specifically have named the unwrapped variable for it's intended use