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

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.

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

How to get the First Character in a name

I have below func in my class.
static func getFirstCharInName(strName: String) -> String {
let firstCharInName = String(strName.first)
return firstCharInName.trim()
}
I encountered this err:
Value of optional type 'Character?' must be unwrapped to a value of type 'Character'
What seems to be the problem?
Thanks
func getFirstCharInName(strName: String) -> String {
let indexStartOfText = strName.index(strName.startIndex, offsetBy: 0)
let indexEndOfText = strName.index(strName.startIndex, offsetBy: 0)
let firstChar = String(strName[indexStartOfText...indexEndOfText])
return firstChar
}
This error means that the expression has optional value (the value can be nil) that is not yet unwrapped, strName.first returns an optional value of Character?, but your function demands a returning type of String which is not an optional type.
So, in order to fix this, you need to unwrap the optional value strName.first, it seems like you are not familiar with optionals, here's the code for your case (choose one from two options):
func getFirstCharInName(strName: String) -> String {
// option 1: force unwrap - can cause fatal error
return String(strName.first!)
// option 2: optional binding
if let firstCharInName = strName.first {
return String(firstCharInName)
} else {
// if the optional value is nil, return an empty string
return ""
}
}
PS. I don't really understand the function trim() in your question, but if you mean to strip away the blank spaces like " ", you can do:
firstCharInName.trimmingCharacters(in: .whitespaces)
Avoid the optional simply with prefix, it's totally safe. if there is no first character you'll get an empty string.
static func getFirstChar(in name: String) -> String { // the function name getFirstChar(in name is swiftier
return String(name.prefix(1))
}
I don't know what the trim function is supposed to do.
It means that value of optional type 'Character?' (as result of your part of code strName.first) must be unwrapped to a value of type 'Character' before you will be gonna cast it to String type.
You may use this variant:
func getFirstCharInName(strName: String) -> String {
return strName.count != 0 ? String(strName.first!) : ""
}
As you can see, the exclamation point is in the string strName.first! retrieves the optional variable as it was needed.
you can do something like that:
extension String {
var firstLetter: String {
guard !self.isEmpty else { return "" }
return String(self[self.startIndex...self.startIndex])
}
}
then
let name = "MilkBottle"
let first = name.firstLetter // "M"

Convert optional string to Int crashes in spite of having value

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

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

How to convert Any to Int in Swift

I get an error when declaring i
var users = Array<Dictionary<String,Any>>()
users.append(["Name":"user1","Age":20])
var i:Int = Int(users[0]["Age"])
How to get the int value?
var i = users[0]["Age"] as Int
As GoZoner points out, if you don't know that the downcast will succeed, use:
var i = users[0]["Age"] as? Int
The result will be nil if it fails
Swift 4 answer :
if let str = users[0]["Age"] as? String, let i = Int(str) {
// do what you want with i
}
If you are sure the result is an Int then use:
var i = users[0]["Age"] as! Int
but if you are unsure and want a nil value if it is not an Int then use:
var i = users[0]["Age"] as? Int
“Use the optional form of the type cast operator (as?) when you are
not sure if the downcast will succeed. This form of the operator will
always return an optional value, and the value will be nil if the
downcast was not possible. This enables you to check for a successful
downcast.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.
https://itun.es/us/jEUH0.l
This may have worked previously, but it's not the answer for Swift 3. Just to clarify, I don't have the answer for Swift 3, below is my testing using the above answer, and clearly it doesn't work.
My data comes from an NSDictionary
print("subvalue[multi] = \(subvalue["multi"]!)")
print("as Int = \(subvalue["multi"]! as? Int)")
if let multiString = subvalue["multi"] as? String {
print("as String = \(multiString)")
print("as Int = \(Int(multiString)!)")
}
The output generated is:
subvalue[multi] = 1
as Int = nil
Just to spell it out:
a) The original value is of type Any? and the value is: 1
b) Casting to Int results in nil
c) Casting to String results in nil (the print lines never execute)
EDIT
The answer is to use NSNumber
let num = subvalue["multi"] as? NSNumber
Then we can convert the number to an integer
let myint = num.intValue
if let id = json["productID"] as? String {
self.productID = Int32(id, radix: 10)!
}
This worked for me. json["productID"] is of type Any.
If it can be cast to a string, then convert it to an Integer.