0

I am trying to convert "status" from below response to Int.

{
    "status": "200",
    "message": "Token successfully generated.",
    "data": {
        "token": "abc"
    }
}

When I try to convert it shows error like Could not cast the value of type '_SwiftValue' to 'NSNumber'.

Here what i have tried in code.

var status:Int = 0
var dict = dictTemp as! Dictionary<String,AnyObject>

if let value = dict["status"] as? String {
    status = value.toInt()!
} else if let value = dict["status"] as? Int {
    status = value
}

//  let status = dictTemp!.value(forKey: "status") as? String ?? ""

if(status == 200)
{
    errorCode = 0
    error = false
}
else
{
    errorCode = 1
    error = true
}

It always goes to else part.

Here I have attached screenshot what I can see in JSON data.

Please help me how I can convert status to Int.

enter image description here

ielyamani
  • 17,807
  • 10
  • 55
  • 90
VDPATEL
  • 416
  • 3
  • 18

2 Answers2

0

I think your issue is because you are using AnyObject instead of Any. Your dictionary must be of type [String: Any].

See this answer here.

AnyObject is only for reference types (classes), Any is for both value and reference types.

Also, since you tagged your question as Swift 4, you should be converting using Int(), not .toInt().

Example:

func getStatus(jsonData: Data) -> Int {
    guard
        let json = try? JSONSerialization.jsonObject(with: jsonData, options: []),
        let dict = json as? [String: Any],
        let statusString = dict["status"] as? String,
        !statusString.isEmpty,
        let status = Int(statusString)
        else {
        return 0
    }

    return status
}
Alejandro Cotilla
  • 2,501
  • 1
  • 20
  • 35
  • Have you checked using `AnyObject` reproduces the same issue as the OP? – OOPer Oct 20 '18 at 13:58
  • Your tip helps me.Thanks a lot – VDPATEL Oct 20 '18 at 14:01
  • @VDPATEL you are welcome. @OOPer I did try it, and I myself experienced this issue in the past. You can try it online on http://online.swiftplayground.run/ where you can choose the Swift version. Anything lower than Swift 4.1 will fail when casting to `[String: AnyObject]`, I think is because you are getting a NSString instead of String. I also have a feeling that the OP was not even on Swift 4 because he was using `toInt()`. So my answer is completely valid. – Alejandro Cotilla Oct 20 '18 at 14:41
  • @AlejandroCotilla, your explanation does not explain whether your answer is valid or not. The OP is not saying that the code fails _when casting to `[String: AnyObject]`_. And `toInt()` is removed from Swift so long ago, that I guess the OP may be using some extension. If you could show me any verifiable proof that, in any version of Swift, your code with `Any` changed to `AnyObject` would show the same issue as the OP, I would change my mind. – OOPer Oct 20 '18 at 14:54
  • @OOPer, "The OP is not saying that the code fails when casting to [String: AnyObject]" - correct, I am the one saying it. And I already told you how to verify my answer. – Alejandro Cotilla Oct 20 '18 at 14:59
  • @AlejandroCotilla, the site you have shown does not make the same result as in Swift 4.1.2 of Xcode 9.4.1. And the OP's question is based on the fact that casting `as! Dictionary` does not cause crash and generated an non-nil result. You need to test your code where that fact is observed. – OOPer Oct 20 '18 at 15:19
  • @OOPer, please go to that site again, select 4.0.3-RELEASE and copy this: https://gist.github.com/acotilla91/3cddb99bf01a3375a6fea6bc283b4f96 – Alejandro Cotilla Oct 20 '18 at 15:28
  • @AlejandroCotilla, In the OP's environment, this code `var dict = dictTemp as! Dictionary` does not crash and generated the non-nil output shown in the debugger image, OK? So, this behavior is the requirement when you test your code. You need to show a solution which works in the same environment as OPs. Try your code with the casting line to `case let dict = json as! [String: AnyObject],`, which runs without crashing on Xcode 9.4.1/Swift 4.1.2. I may need to correct my words, test your code _in any version of Swift **which shows the same behavior as the observed fact**_. – OOPer Oct 20 '18 at 15:44
  • @OOPer, I may need to correct my words also, I never said that casting to `[String: AnyObject]` crashes, I'm saying that in previous Swift versions casting to `[String: AnyObject]` will give you a dictionary with string values that you could not run `.toInt()` on them without doing some extra work. @VDPATEL you mind letting us know which Swift version are you using? – Alejandro Cotilla Oct 20 '18 at 16:05
  • `toInt()` is removed in Swift 2, and the OP has tagged swift4. Without any extension the method does not work. So, _casting to `[String: AnyObject]`_ has nothing to do with `toInt()`. You can download older Xcodes, 9.1 for Swift 4.0.2, 9.4.1 for Swift 4.1.2. Try and see what you get with exactly the same code with Swift versions of actual Xcode. The OP may be misusing `Any` or `AnyObject` outside the shown code, which may cause the issue described, so your answer is very suggestive. But if you insist on using `[String: Any]` as a direct solution, I may need to say it is wrong. – OOPer Oct 20 '18 at 16:15
  • I meant `.toInt()`/`Int()` and probably other `String` operations. And you'll get the same issue on anything lower than Swift 4.1 like I mentioned above, that includes 4.0.x. – Alejandro Cotilla Oct 20 '18 at 16:21
  • @AlejandroCotilla, please clarify the Xcode version which I can get the same issue, of course you may need to download and test it by yourself before writing comments to me. – OOPer Oct 20 '18 at 17:09
0

Use structs it is much safer:

let json = """
{
    "status": "200",
    "message": "Token successfully generated.",
    "data": {
        "token": "abc"
    }
}
"""

guard let jsonData = json.data(using: .utf8) else {
    fatalError("Couldn't convert the json to data")
}

struct Response: Codable {
    let status, message: String
    let data: TokenData
}

struct TokenData: Codable {
    let token: String
}

do {
    let decoded = try JSONDecoder().decode(Response.self, from: jsonData)
    if let status = Int(decoded.status) {
        print(status)
    } else {
        fatalError("The status is not an integer")
    }
} catch {
    print(error)
}
ielyamani
  • 17,807
  • 10
  • 55
  • 90