Swift 3 optional string to int - ios

I am using Vapor for Swift backend. Following is the code i am working with.
drop.post("postTodo") { request in
var jsonContent: JSON?
if let contentType = request.headers["Content-Type"], contentType.contains("application/json"), let jsonData = request.json {
jsonContent = jsonData
print("Got JSON: \(jsonContent)")
}
guard let id = jsonContent?.node.object?["id"]?.string
else {
return JSON(["message": "Please include mandatory parameters"])
}
let tempId = Int(id)!
I am getting "id" as optional string for eg: Optional("123") for jsonContent?.node.object?["id"]?.string
When I try to convert it to int using Int(id)! i get back nil
If i try to do let tempId = Int(id!) it gives error.
But when i do the same thing in playground i get proper int value.
let id: String?
id = "1234"
let myInt = Int(id!)
Why Optional string to Int is not working properly in my Vapor app ?
Any idea.

If "id" is an optional string, then you probably don't want to be force unwrapping it with the "!".
The safest approach would be something like:
if let id = id
{
let myIdAsInt = Int(id)
}
The reason it "works" in the playground, is you are definitely assigning a non-nil value to the string (therefore you get away with the force unwrap).

String!might contain a string, or it might contain nil. It’s like a regular optional, but Swift lets you access the value directly without the unwrapping safety. If you try to do it, it means you know there’s a value there – but if you’re wrong your app will crash.
var optionalString: String? = "123"
// first check if it doesn't contain nil
if let str = optionalString {
// string to -> Int
if let id = Int(str) {
print(id) // work with id
}
} else {
// optionalString contains nil
}

what i found is in my iOS code i had a struct with optional properties coz of which when mapped to Dict gave object with optional values to keys.
If I make properties non optional and send it to vapor backend after it works fine.
So basically it was the case of using Optionals properly.

Related

convert value of type 'String' to expected argument type 'Int'

I have a dictionary of data passed from another viewController, and when I tried to fetch the id from the dictionary it gives me conversion error!
var comments = [JSON]()
#IBAction func AddCommentBTN(_ sender: Any) {
let commentTXT = CommentTXTField.text
let name = self.accountDetails["name"]
let email = self.accountDetails["email"]
let articleId = self.comments["id"].string! ----> error is here
API.AddComment(articleId: "", name: name!, email: email!, message: commentTXT!) { (error: Error?, success: Bool) in
if success {
self.CommentTableView.reloadData()
print("Registerd Successfuly")
} else {
print("Faile To Comment")
}
}
}
Firstly, self.comments is an array of JSON object. So before getting value from the JSON you need to get the object first from the array. Before getting the 0 index value make sure the array contains value.
Seems like you are using SwiftyJSON to parse the value. So by using .intValue you can get the Int value. .intValue will return a Int type value. If the key not present there then this will return you the 0 value. .intValue not an Optional type.
Try this
let articleId = self.comments[0]["id"].intValue
instead of
let articleId = self.comments["id"].string!
You are converting a String to Int which is not as straightforward as you may think. The String can contain characters that is not a number like "Forest". To convert a String to Int you can use:
if let myInt = Int(self.comments["id"]) {
let articleId = myInt
}
It will check if the string is a correct Int and return an Optional value. You can also use a fallback to define a default value if the String is not correct Int
let myInt = Int(self.comments["id"]) ?? 0
That means “attempt to convert self.comments["id"] to an integer, but if the conversion failed because it contained something invalid then use 0 instead.”
The values of a json are optional and might be on any allowed type. A way parsing this save would be getting the value for "id", which will be an optional, and try to convert this optional to an Int. The Int itself is optional as well. (Short, it might be there or not)
guard let value = self.comments["id"], let articleId = Int64(value) else {
// Not valid
return
}
print(articleId)
A better way would be parsing your json data to an object in the first place. Your controller would not need to deal with the parsing of optional data, but instead just get the right data from the object.

Get String value from an optional in Swift 4

I am new to Swift and am trying to compare my Error description name with different String constants to show the user different results, based on the error.
I am using:
let errorName = errors.first?["name"].debugDescription
The value of errorName comes as "Optional(AlreadyActiveUser)" and when i compare this to my constant string "AlreadyActiveUser", i get false.
I have tried many things, but i am not able to get the value of the string inside the optional.
Someone, please help.
You can use optional binding in this case...
guard let errorName = errors.first?["name"].debugDescription as? String {
print("value is not present...")
return
}
print(errorName)
//here you can compare errorName == "AlreadyActiveUser"
you can use this
if let errorName = errors.first?["name"] as? String {
print(errorName)
//here you can compare errorName == "AlreadyActiveUser"
}
else
{
print("value is not present...")
}
try let errorName = errors.first!["name"].debugDescription
Notes that I forced wrapping first with ! instead of ?.

Unwrapping a optional in swift which is an optional but swift doesn't know its a optional

I'm working on an app to convert model paint color's. I just got coreData to work and now I ran into a different problem.
let colorL: String = String(color.valueForKey("revell"))
let AmountL: String = String(color.valueForKey("filled"))
print(colorL)
print(AmountL)
cell.ColorLabel.text = colorL
cell.AmountLabel.text = AmountL
This is my code for the tableview. and my console output is this
Optional(68)
Optional(g)
and so the problem is if you haven't guessed yet that I need to unwrap a optional that cannot be unwrapped because swift doesn't know it is a optional and I keep on getting a error that I can't unwrap a non-optional.
valueForKey returns an optional (AnyObject? to be specific). Unwrap that and then build a string with it.
if let value = color.valueForKey("revell") as? /* Some Type */ {
let amountL: String = String(value)
// ...
}
let colorL: String = (color.valueForKey("revell")?.description)!
let AmountL: String = (color.valueForKey("filled")?.description)!
print(colorL)
print(AmountL)
ColorLabel.text = colorL
AmountLabel.text = AmountL

Remove Optional Alamofire (and anywhere)

I'm trying to implement a new REST service in Swift but i'm lost. I need remove "Optional" string in my service receeipt:
func callServiceReceives(){
var jsonReceived: JSON = []
Alamofire.request(.GET, "http://localhost:8080/userServicesProvider")
.responseJSON { (_, _, pruebaJSON, _) in
jsonReceived = JSON(pruebaJSON!)
println(jsonReceived["recibos"].array?.count) // "Optional(4)"
}
}
// If i try if let temp:String! = String(stringInterpolationSegment: jsonReceived["recibos"].array?.count) {
// println(temp) -> "Optional(4)"
// } -> say me "Bound value in a conditional binding must be of Optional type"
//If i try -> let temp:String! = String(stringInterpolationSegment: jsonReceived["recibos"].array?.count)
//
// if let temp2 = temp!{
// println(temp2) -> "Optional(4)"
//} -> i had the same problem: "Bound value in a conditional binding must be of Optional type"
Can you help me please?
Thanks a lot
You're putting your ! in the wrong place. It should be here:
println(jsonReceived["recibos"].array?.count!)
For safety's sake, though, you might be better off with:
println(jsonReceived["recibos"].array?.count.map{String($0)} ?? "Error")
Which will print "Error" if your array is nil, or:
jsonReceived["recibos"].array?.count.map(println)
Won't print anything if your array is nil.
You are getting a optional because your array is optional.
Try printing println(jsonReceived[“recipes”].array!.count)
This however isn’t the best way to do it. You should use an if let statement to check if your array is not nil. After that you can get the count of the new let. This won’t be an optional anymore.
if let temp = jsonReceived[“recipes”].array{
println(temp.count)
}
If you don't need to know if there's a difference between an empty array and no array at all....
let count = jsonReceived["recibos"].array?.count as? Int ?? 0

Swift optionals: language issue, or doing something wrong?

I am doing what I believe to be a very simple task. I'm trying to get a value out of a dictionary if the key exists. I am doing this for a couple keys in the dictionary and then creating an object if they all exist (basically decoding a JSON object). I am new to the language but this seems to me like it should work, yet doesn't:
class func fromDict(d: [String : AnyObject]!) -> Todo? {
let title = d["title"]? as? String
// etc...
}
It gives me the error: Operand of postfix ? should have optional type; type is (String, AnyObject)
HOWEVER, if I do this, it works:
class func fromDict(d: [String : AnyObject]!) -> Todo? {
let maybeTitle = d["title"]?
let title = maybeTitle as? String
// etc...
}
It appears to be basic substitution but I may be missing some nuance of the language. Could anyone shed some light on this?
The recommended pattern is
if let maybeTitle = d["title"] as? String {
// do something with maybeTitle
}
else {
// abort object creation
}
It is possibly really a question of nuance. The form array[subscript]? is ambiguous because it could mean that the whole dictionary (<String:AnyObject>) is optional while you probably mean the result (String). In the above pattern, you leverage the fact that Dictionary is designed to assume that accessing some key results in an optional type.
After experimenting, and noticing that the ? after as is just as ambiguous, more, here is my solution:
var dictionary = ["one":"1", "two":"2"]
// or var dictionary = ["one":1, "two":2]
var message = ""
if let three = dictionary["three"] as Any? {
message = "\(three)"
}
else {
message = "No three available."
}
message // "No three available."
This would work with all non-object Swift objects, including Swift Strings, numbers etc. Thanks to Viktor for reminding me that String is not an object in Swift. +
If you know the type of the values you can substitute Any? with the appropriate optional type, like String?
There are a few of things going on here.
1) The ? in d["title"]? is not correct usage. If you're trying to unwrap d["title"] then use a ! but be careful because this will crash if title is not a valid key in your dictionary. (The ? is used for optional chaining like if you were trying to call a method on an optional variable or access a property. In that case, the access would just do nothing if the optional were nil). It doesn't appear that you're trying to unwrap d["title"] so leave off the ?. A dictionary access always returns an optional value because the key might not exist.
2) If you were to fix that:
let maybeTitle = d["title"] as? String
The error message changes to: error: '(String, AnyObject)' is not convertible to 'String'
The problem here is that a String is not an object. You need to cast to NSString.
let maybeTitle = d["title"] as? NSString
This will result in maybeTitle being an NSString?. If d["title"] doesn't exist or if the type is really NSNumber instead of NSString, then the optional will have a value of nil but the app won't crash.
3) Your statement:
let title = maybeTitle as? String
does not unwrap the optional variable as you would like. The correct form is:
if let title = maybeTitle as? String {
// title is unwrapped and now has type String
}
So putting that all together:
if let title = d["title"] as? NSString {
// If we get here we know "title" is a valid key in the dictionary, and
// we got the type right. title has now been unwrapped and is ready to use
}
title will have the type NSString which is what is stored in the dictionary since it holds objects. You can do most everything with NSString that you can do with String, but if you need title to be a String you can do this:
if var title:String = d["title"] as? NSString {
title += " by Poe"
}
and if your dictionary has NSNumbers as well:
if var age:Int = d["age"] as? NSNumber {
age += 1
}

Resources