Search code examples
swiftxcodejson-serialization

Swift : JSONSerialization.jsonObject not working for json into json


I am using this code for geting json data from url:

URLSession.shared.dataTask(with:request, completionHandler: { (data, response, error) in
 guard let data = data, error == nil else { return }

 do {           
   let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:String]
   completion(json)              
 } catch _ as NSError {
   completion(nil)
 }
}).resume()

If my json is {"error":"true","message":"no"} it works fine

But if i use json into json, it not works :

{"error":"true","message":"no","state":{"id":"1","name":"empty"}}

Solution

  • Using as! [String:String] you are saying that all values in the dictionary will be of String type, but the nested JSON related to the state key is obviously not a String

    use as? [String: Any] and then cast your other properties as needed. result["error"] as String

    Using this method it makes getting the nested data more difficult than it needs to be:

    if let state = result["state"] as? [String: String] {
        let name = state["name"]
        let value = state["value"]
    }
    

    Notes

    1. When using Swift 4 or greater you should be using the Codable Protocol
    2. You should not be force unwrapping, use conditional unwrapping (as? [String: Any])

    EDIT:

    An example of how you can do this using Codable and how it is used.

    Playground code

    // you dont need this part, I am not making network request
    let jsonData = """
    {"error":"true","message":"no","state":{"id":"1","name":"empty"}}
    """.data(using: .utf8)
    
    struct ErrorState: Codable
    {
        let id: String
        let name: String
    }
    
    struct ErrorResponse: Codable
    {
        let error: String
        let message: String
        let state: ErrorState
    }
    
    guard let data = jsonData else { fatalError() }
    
    let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: data)
    print(errorResponse?.state.name)