How to check nil for Swift Optionals with out unwrap it? - swift

I knew that safely unwrapping is as follows
var firstName:String?
if let firstName = firstName
{
dictionary.setObject(firstName, forKey: "firstName")
}
else
{
dictionary.setObject("", forKey: "firstName")
}
I want to add firstname to dictionary even it is nil also. I will have 10-15 var's in dictionary.
I do not want to check for this condition 10-15 times for ear var.
I am having more than 1000 optionals through out project.
So thought of writing writing a func will help me duplicate the code and reduce the number of lines.
So implemented this func as below.
func checkNull(str:String) -> String
{
return str.characters.count > 0 ? "\(str)" : ""
}
but while calling the func,
let addressstr = self.checkNull(address?.firstName)
firstname is the var in address model here.
The auto correction sugguests
let addressstr = self.checkNull((address?.firstName)!)
The above line causes the crash.

First of all firstName is an Optional therefore you cannot pass it to a function which only takes String.
In addition this line:
str.characters.count > 0 ? "\(str)" : ""
Is equivalent to just returning str so you don't check whether it is an Optional.
Solution
In this case it is way easier to use the nil coalescing operator:
let addressstr = address?.firstName ?? ""
If address is not nil firstName gets unwrapped and bind to addressstr. Otherwise this string gets assigned to it: ""

Related

How to remove optional from a string value in swift?

In the code I'm not able to remove optional from the value inside the lbltotalamount.
The value in lblTotalAmount is not removing its optional value from it.
Why? The value in grandtotal gets optional removed but when I assign it to a label it returns an optional value again.
The lblTottalAmount is getting an optional value. I want to remove it.
if success == false {
var grandtotal: Any? = value["total"]
if grandtotal != nil {
print("O!O!O!O/\(grandtotal!)")
grandtotal = String(describing: grandtotal)
self.lblTotalAmount.text = ([grandtotal]) as! String // (here I am not able to remove optional)
}
The problem is in the line
grandtotal = String(describing: grandtotal)
You check for nil but you don't unwrap the value so it's still an optional.
And you are misusing String(describing. Never use it for types which can be converted to String with an init method.
Use always conditional downcast
if success == false {
if let grandtotal = value["total"] as? Double {
self.lblTotalAmount.text = String(grandtotal)
}
}

Understanding comparing optional strings

I'm using the following code:
let optionalString:String? = ""
print(optionalString == nil)
The optional String contains a null value. When comparing it, however, it prints false. I don't understand why this is the case when running the program. Can someone please explain why this is happening?
This "" is not a nil value
let optionalString:String?=""
it would be if you declared it like this
var optionalString:String?
An optional in Swift is a type that can hold either a wrapped value or nil
var name:String?
var name:String? = nil
name is of type optional and may have String value or a nil value
name now is nill
name = ""
name is an optional string has this "" value
NOTE : "" is a value is an empty string not nil but "" != " " != " " ,etc
If you want to instantiate your string as null, then you should declare it as so
var optionalString: String? = nil
Creating it as a let would be literally meaningless as you would be instantiating a nil value that can never be changed.

Is If let Evaluated Differently from If Statement?

Is if let kind of if statement, or is if let different?
Does the compiler treat if let and if statement differently?
if let is for unwrapping optional values.
if is for evaluating a condition
var example: String? = "rick"
if let name = example{
print(name) //name is the unwrapped version of example
}
If example is nil (no value), then the if let statement will fall through and the code inside of it will not run.
var example: Bool = true
if example{
print("Example is true")
} else{
print("Example is false")
}

How can I fix this Result values in '? :' expression have mismatching types 'String' and '[Any]?'

I have the following lines of code:
let string:String = ""
let extracted_data:String! = (response?.extracted_data == nil) ? "" : response?.extracted_data
string.append("\(extracted_data)")
extracted_data is a [Any]. I can't figure out why I am getting this error:
Result values in '? :' expression have mismatching types 'String' and '[Any]?'
You should be parsing your variable as a [Any] type of array and later on if you know that your array contains string type you should be doing like this. Take a first element out of array and set your value
response?.extracted_data?.first as? String ?? "Default Value if string is not present"
The values returned by the ternary operator ? : need to be the same type, because Swift needs to know at compile time what type extracted_data will be. You are attempting to return either a String or [Any]?. To fix this, return an empty array [] instead of an empty string "" for the nil case. Also, you need to unwrap response so that response!.extracted_data returns [Any] instead of [Any]?. Although force unwrapping with ! can lead to crashes, this is safe because you already know response is not nil due to your check.
var string: String = "" // This needs to be a var for append to work
let extracted_data = response?.extracted_data == nil ? [] : response!.extracted_data
string.append("\(extracted_data)")
print(string)
Now look at this line:
let extracted_data = response?.extracted_data == nil ? [] : response!.extracted_data
Swift has a better way of doing that with a special nil coalescing operator ??. It is used to unwrap an optional value or to supply a default value for when that value is nil. Using ??, the line becomes:
let extracted_data = response?.extracted_data ?? []
I assume this is a simplified example, because you could just assign to string instead of appending. In either case, string needs to be a var to be modified and its type can be inferred . Here is the final version of the code:
var string = ""
let extracted_data = response?.extracted_data ?? []
string.append("\(extracted_data)")
print(string)
Perhaps you don't want the [] that prints when response == nil. In that case, have ? : return a String like so:
var string = ""
let extracted_data = response == nil ? "" : "\(response!.extracted_data)"
string.append(extracted_data)
print(string)
If you want to print just the first item of your [Any] array, and it can really be of any type, then you can do this:
var string = ""
let first = response?.extracted_data.first
let extracted_data = first == nil ? "" : "\(first!)"
string.append(extracted_data)
print(string)

Swift Optional Dictionary [String: String?] unwrapping error

So here I have a basic setup
var preferenceSpecification = [String : String?]()
preferenceSpecification["Key"] = "Some Key"
preferenceSpecification["Some Key"] = nil
preferenceSpecification["DefaultValue"] = "Some DefaultValue"
print(preferenceSpecification)
var defaultsToRegister = [String : String]()
if let key = preferenceSpecification["Key"], let defaultValueKey = preferenceSpecification["DefaultValue"] {
defaultsToRegister[key] = preferenceSpecification[defaultValueKey]!
}
But the error points out where it demands that I force unwrap this, to be like this:
defaultsToRegister[key!] = preferenceSpecification[defaultValueKey!]!
Which doesn't make sense, because keyValue and defaultValue already are unwrapped
When you extract a value from a dictionary like this using subscript
[String: String?]
you need to manage 2 levels of optional. The first one because the subscript returns an optional. The second one because the value of you dictionary is an optional String.
So when you write
if let value = preferenceSpecification["someKey"] {
}
you get value defined as an optional String.
Here's the code to fix that
if let
optionalKey = preferenceSpecification["Key"],
key = optionalKey,
optionalDefaultValueKey = preferenceSpecification["DefaultValue"],
defaultValueKey = optionalDefaultValueKey,
value = preferenceSpecification[defaultValueKey] {
defaultsToRegister[key] = value
}
Suggestions
You should avoid force unwrapping as much as possible. Instead you managed to put 3 ! on a single line!
You should also try to use better name for your constants and variables.
You could also define an extension which helps get rid of the double optional situation.
extension Dictionary where Value == Optional<String> {
func flattened(_ key: Key) -> Value {
if let value = self[key] {
return value
}
return nil
}
}
Usage: preferenceSpecification.flattened("someKey")