Convert optional string to Int crashes in spite of having value - swift4

I check the optional string
print(limitCash)
if let value = Int32(limitCash) {
aProvider.limitBuy = value
}
The value of limitCash is Optional("500").
The program checks if let statement and skips it without assigning value.
Program crashes if I try aProvider.limitBuy = Int32(limitCash)!

First you need to unwrap String? to String and then unwrap the result of casting from String to UInt32 (that will be Uint32?).
print(limitCash)
if let stringValue = limitCash {
if let value = Int32(stringValue) {
print(value) // 500
}
}

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)
}
}

Swift Convert Optional String to Int or Int32 (Unwrapping optionals question)

I am trying to read a string and convert it to an int. I have a solution but it seems way too complicated. I guess I am still trying to wrap my head around unwrapping.
I have posted code below along with the compiler errors that I get with each solution.
In this example I try to read a string from UserDefaults and convert to an integer value.
static func GetSelectedSessionNum() -> Int32 {
var sessionNum : Int32 = 0
let defaults = UserDefaults.standard
let optionalString: String? = defaults.string(forKey: "selectedSessionNum")
// this works but it's too complicated
if let string = optionalString, let myInt = Int32(string) {
return myInt
}
return 0
// Error : optional String? must be unwrapped to a value of type 'String'
let t : String = defaults.string(forKey: "selectedSessionNum")
if let s : String = defaults.string(forKey: "selectedSessionNum") {
// error - Int32? must be unwrapped to a value of Int32
return Int32(s)
}
return 0
}
You need to cast to non optional Int32 in order to match your return type.
You can use any optional binding approach, or change your return type to Int32?
If you want an uncomplicated solution save selectedSessionNum as Int
static func getSelectedSessionNum() -> Int32 {
return Int32(UserDefaults.standard.integer(forKey: "selectedSessionNum"))
}
otherwise double optional binding
if let string = UserDefaults.standard.string(forKey: "selectedSessionNum"), let myInt = Int32(string) {
return myInt
}
or the nil coalescing operator
if let string = UserDefaults.standard.string(forKey: "selectedSessionNum") {
return Int32(string) ?? 0
}
is the proper way
If you want to avoid optional bindings, you can use flatMap, when called on Optional's it allows you to convert one optional to another:
return UserDefaults.standard.string(forKey: "selectedSessionNum").flatMap(Int32.init) ?? 0
You'd also need the ?? (nil coalescing operator) to cover the scenarios where either the initializer fails, or the value is not present in user defaults.

Convert Int16 to String Swift 4

I am trying to convert an Int16 value to String but it gives value with Optional, won't allow me to forced unwrap it.
String(describing:intValue)
Result : Optional(intValue)
Unwrap intValue first, then pass it to the string initializer: String(unwrappedIntValue)
Here are some ways of handling the optional. I've added explicit string# variables with type annotations, to make it clear what types are involved
let optionalInt: Int? = 1
// Example 1
// some case: print the value within `optionalInt` as a String
// nil case: "optionalInt was nil"
if let int = optionalInt {
let string1: String = String(int)
print(string1)
}
else {
print("optionalInt was nil")
}
// Example 2, use the nil-coalescing operator (??) to provide a default value
// some case: print the value within `optionalInt` as a String
// nil case: print the default value, 123
let string2: String = String(optionalInt ?? 123)
print(string2)
// Example 3, use Optional.map to convert optionalInt to a String only when there is a value
// some case: print the value within `optionalInt` as a String
// nil case: print `nil`
let string3: String? = optionalInt.map(String.init)
print(string3 as Any)
// Optionally, combine it with the nil-coalescing operator (??) to provide a default string value
// for when the map function encounters nil:
// some case: print the value within `optionalInt` as a String
// nil case: print the default string value "optionalInt was nil"
let string4: String = optionalInt.map(String.init) ?? "optionalInt was nil"
print(string4)
You can convert a number to a String with string interpolation:
let stringValue = "\(intValue)"
Or you can use a standard String initializer:
let stringValue = String(intValue)
If the number is an Optional, just unwrap it first:
let optionalNumber: Int? = 15
if let unwrappedNumber = optionalNumber {
let stringValue = "\(unwrappedNumber)"
}
Or
if let unwrappedNumber = optionalNumber {
let stringValue = String(unwrappedNumber)
}

Trouble converting a string to an Int

The following works in Playground:
func stringToInt(numberStr: String!) -> Int {
print(numberStr)
return Int(numberStr)!
}
let strNum1: String?
strNum1 = "1"
let result = stringToInt(numberStr: strNum1)
It returns 1 as expected.
In Xcode, a similar approach fails:
func stringToInt(numberStr: String!) -> Int {
print("\(numberStr!)")
let str = "\(numberStr!)"
print(Int(str))
return Int(str)!
}
The first print produces: Optional(1)
The second print produces: nil
The return statement fails because it is attempting to create an Int from a nil.
It must be something simple but I haven't been able to determine why it's not working. This is in Swift 3 and Xcode 8 BTW.
#Hamish:
In Xcode, I have a string with a numeric value. This:
print("number: (selectedAlertNumber) - unit: (selectedAlertUnit)")
...produces this:
number: Optional(1) - unit: Day
Then, I'm checking to see if either selectedAlertNumber of selecterAlertUnit != "-"
if selectedAlertNumber != "-" && selectedAlertUnit != "-" {
// set alert text
var unitStr = selectedAlertUnit
let alertNumber = stringToInt(numberStr: selectedAlertNumber)
if alertNumber > 1 {
unitStr.append("s")
}
let alertText = "...\(selectedAlertNumber) \(unitStr) before event."
alertTimeCell.setAlertText(alertText: alertText)
// set alert date/time
}
The let alertNumber = stringToInt... line is how I'm calling the function. I could just attempt the conversion there but I wanted to isolate the problem by wrapping the conversion in it's own function.
Using string interpolation to convert values to a String is usually not advised since the output may differ depending on optional status of the value. For example, consider these two functions:
func stringToInt(numberStr: String!) -> Int
{
print("\(numberStr!)")
let str = "\(numberStr!)"
return Int(str)!
}
func otherStringToInt(numberStr: String!) -> Int
{
print(numberStr)
let str = "\(numberStr)"
return Int(str)!
}
The only difference between these two is the ! in the second function when using string interpolation to get a String type value from numberStr. To be more specific, at the same line in function 1 compared to function 2, the string values are very different depending on whether or not the interpolated value is optional:
let str1: String = "1"
let str2: String! = "1"
let str3: String? = "1"
let otherStr1 = "\(str1)" // value: "1"
let otherStr2 = "\(str2)" // value: "Optional(1)"
let otherStr3 = "\(str2!)" // value: "1"
let otherStr4 = "\(str3)" // value: "Optional(1)"
let otherStr5 = "\(str3!)" // value: "1"
Passing otherStr2 or otherStr4 into the Int initializer will produce nil, since the string "Optional(1)" is not convertible to Int. Additionally, this will cause an error during the force unwrap. Instead of using string interpolation in your function, it would be better to just use the value directly since it's already a String.
func stringToInt(numberStr: String!) -> Int
{
return Int(numberStr)!
}
Let me know if this makes sense.
Also, my own personal feedback: watch out force unwrapping so frequently. In many cases, you're running the risk of getting an error while unwrapping a nil optional.

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")