Cannot properly convert value from JSON dictionary - ios

I'm stuck on a weird problem.
I'm parsing a JSON response via Alamofire, and want to fetch a variable that just keeps throwing errors regardless whether I cast it to a String or Number, whilisting changing the error message every time I do :/
If I cast it to a String like this:
let kolicina = jsonCategory["kolicina"] as! String
if Int(kolicina) > 0 {
I get the error:
"Could not cast value of type '__NSCFNumber' (0x10f051368) to 'NSString' (0x10e627b48)."
When I try to cast it to a NSNumber:
let kolicina = jsonCategory["kolicina"] as! NSNumber
if kolicina.integerValue > 0 {
I get:
"Could not cast value of type 'NSTaggedPointerString' (0x10effcae8) to 'NSNumber' (0x10e5d32a0)."
This is what I get for that specific variable when I print the Dictionary:
kolicina = 0;
Can someone point me in the right direction?

It seems you have a combination of strings and integers in there. I would recommend you to fix the JSON and keep the data either as a string or a number, not both.
If you want to parse such a format, you will have to try to parse it as a NSNumber or as a NSString, e.g.:
let kolicina = jsonCategory["kolicina"]
if let kolicinaString = kolicina as? String {
...
} else if let kolicinaInt = kolicina as? Int {
...
}
with the > 0 checks you could do something like this:
if let kolicinaString = kolicina as? String,
kolicinaInt = Int(kolicinaString) where kolicinaInt > 0 {
print("String: \(kolicinaInt)")
} else if let kolicinaInt = kolicina as? Int where kolicinaInt > 0 {
print("Int: \(kolicinaInt)")
}
or using a ternary operator:
let kolicinaInt = (kolicina is String) ? Int(kolicina as! String) : kolicina as? Int
if kolicinaInt > 0 {
print("Kolicina: \(kolicinaInt)")
}

Try this .. don't make force unwrap
if let kolicina = jsonCategory["kolicina"] as? Int{
// Success: your kolicina is Int
print(kolicina)
}
else{
// Not an Int
}

Related

Swift NSDictionary Child types

I'm having a lot of frustration with Swift when it comes to working with Dictionaries and NSDictionaries.
I am pulling data from a server. One of the values is a Bool.
I started with a Swift Dictionary and moved to NSDictionary out of frustration. However, I still cannot get the values from the dictionary.
All of the following fail with contradictory errors:
let unread:Bool = data!["unread"] as! Bool
let unread:Bool = data?["unread"] as! Bool
let unread:Bool = data?.objectForKey("unread") as! Bool
let unread:NSNumber = data?["unread"] as! NSNumber
error: Could not cast value of type 'NSTaggedPointerString' (0x110c1eae8) to 'NSNumber' (0x10e0ab2a0).
Okay, looks like that data is coming in as a String... let's try:
let unreadStr:String = data!["unread"] as! String
let unreadStr:NSString = data!["unread"] as! NSString
error: Could not cast value of type '__NSCFBoolean' (0x1097413b8) to 'NSString' (0x106bcdb48).
So I'm confused. When I try to convert it to a Bool it says I cannot convert a String to a Number. When I try to convert it to a String, it says I cannot convert a number to a string.
Here is what the data looks like:
Optional({
senderId = 10154040;
sent = 1460844986973;
text = "Test Message 1";
unread = false;
})
You should try something along these lines:
let data: [String : Any] = ["first" : "test", "second" : 2, "third" : true]
let first = data["first"] as! String
let second = data["second"] as! Int
let third = data["third"] as! Bool
print(first)
print(second)
print(third)

How can I set a string as a Null in swift, when server is returning null value?

let debitCardNum = responseObject!["card_number"] as! String
This is my code and I am getting this error
Could not cast value of type 'NSNull' (0x384db1b4) to 'NSString'
(0x384e073c).
use let do like
if let Value = responseObject!["card_number"] as? String {
debitCardNum = Value
}
else
{
//error
}
This is a good candidate for optionals.
let debitCardNum = responseObject["card_number"] as? String
Later on when you want to do something use an if let to ensure the variable has a value
if let debitCardNum = debitCardNum {
// do something
}

if let with OR condition

Is it possible to use an "OR" condition using Swift's if let?
Something like (for a Dictionary<String, AnyObject> dictionary):
if let value = dictionary["test"] as? String or as? Int {
println("WIN!")
}
This would make no sense, how would you be able to tell whether value is an Int or a String when you only have one if statement? You can however do something like this:
let dictionary : [String : Any] = ["test" : "hi", "hello" : 4]
if let value = dictionary["test"] where value is Int || value is String {
print(value)
}
(Tested in Swift 2.0)
You can also do this if you need to do different things depending on the types:
if let value = dictionary["test"] {
if let value = value as? Int {
print("Integer!")
} else if let value = value as? String {
print("String!")
} else {
print("Something else")
}
}
Unfortunately to my knowledge you cannot. You will have to use two separate if statements.
if let value = dictionary["test"] as? String {
doMethod()
} else if let value = dictionary["test"] as? Int {
doMethod()
}
There are multiple ways of getting around this problem. This is just one of them.
Please refer to the Apple documentation on Optional Chaining for more information on this special type of if statement. This is with using Swift 1.2

Type 'String' does not conform to protocol 'NSCopying' error when downcast AnyObject to String

I'm tring to parse a JSON format like this:
{
"key_1" : {
"key_2" : "value"
}
}
and then assign "value" to a variable.
Here is my code:
var variableShouldBeAssigned: String
if let x = (jsonResult["key_1"]? as? NSDictionary) {
if let y = (x["key_2"]? as? String) {
variableShouldBeAssigned = y
}
}
However, an error occurs when I try to downcast from x["key_2"]? to a String, but it's fine to downcast from jsonResult["key_1"]? to an NSDictionary.
I can solve the error by using x["key_2"] to replace x["key_2"]?, but I don't really know why it only works for jsonResult["key_1"]?.
Can anybody tell me the reason?
String does not conform to NSCopying, but surely NSString does!
Also, going from NSString to String is instantaneously implied...
So I would say try something like this... Change String to NSString
here is a sample, assuming that you handle the jsonResult as a NSDictionary...
func giveDictionary(jsonResult:NSDictionary) -> String?
{
if let x = (jsonResult["key_1"]? as? NSDictionary)
{
if let y = (x["key_2"]? as? NSString)
{
return y
}
}
return nil
}
You can simplify all your type checking by using a Swift dictionary at the beginning:
var variableShouldBeAssigned: String
if let dict = jsonResult as? [String:[String:String]] {
if let key1Dict = dict["key_1"] {
if let value = key1Dict["key_2"] {
variableShouldBeAssigned = value
}
}
}
In fact, you can even combine the two last if statements:
var variableShouldBeAssigned: String
if let dict = jsonResult as? [String:[String:String]] {
if let value = dict["key_1"]?["key_2"] {
variableShouldBeAssigned = value
}
}
In general, you should using Swift Dictionaries instead of NSDictionary

swift Dictionary error

I have this func:
typealias KeyValue = Dictionary<String,AnyObject>
func response( response: NSHTTPURLResponse!, data: AnyObject!, error: NSError! ) {
var resData = data as NSDictionary
if( resData["status"] as Int == 1 ){
var content = resData["content"] as Array<KeyValue>
for player in content {
let id : Int = player["id"]
let score : Int = player["score"]
let name : String = player["name"]
players[ id ]!.setName( name )
players[ id ]!.setScore( score )
}
} else {
println( resData["error"] )
}
self.playersList.reloadData()
}
and i'm getting this error:
'(String, AnyObject)' is not convertible to 'Int'
on this lines
let id : Int = player["id"]
let score : Int = player["score"]
let name : String = player["name"]
I can't figure out why
content is Array
-> player is KeyValue
-> player is Dictionary
-> player["id"] is AnyObject
so why he think that player["id"] is '(String, AnyObject)'??
Thanks
UPDATE
Change to this fix that error:
let id = player["id"]! as Int
let score = player["score"]! as Int
let name = player["name"]! as String
But now i'm getting this in run-time:
Thread 5: EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT,subcode=0xdefe)
player in your loop is an instance of Dictionary<String, AnyObject>. So values stored in that dictionary are instances of AnyObject.
In this line:
let id : Int = player["id"]
you are trying to make an implicit cast from AnyObject to Int, which is not possible. The correct way to handle that is to:
Unwrap the value extracted from the dictionary (it can be nil if the key doesn't exist)
explicitly cast to Int
So that line should be fixed as follows:
let id : Int = player["id"]! as Int
which can also be shortened as:
let id = player["id"]! as Int
Similar rules apply for score and name
Addendum - as per your last error, probably it is caused by the fact that a key is not in the dictionary. Try using optionals like this:
let id = (player["id"] as AnyObject?) as? Int
let score = (player["score"] as AnyObject?) as? Int
let name = (player["name"] as AnyObject?) as? String
You have 3 optional variables, which get nil if the corresponding expression at the right side evaluates to nil. If that works, use the debugger to check which key is not in the dictionary

Resources