Betül Demirci
Betül Demirci

Reputation: 1

Swift 4 parsing nested JSON arrays which is the response from web service

Here is my JSON which is the response from web service,

{
"Data": [
    {
        "Id": 181670,
        "PatientId": 10086,
        "Form": "{\"Day\":\"14-11-2019\",\"Hour\":\"08:31\"}",
        "Type": 8,
        "Time": "2019-11-14T08:31:00"
    }
],
"Success": true,
"ErrorMessage": null

}

Here is the structure I want it saved to

struct Response: Decodable{

let ErrorMessage: String?
let Success: Bool
var data: [Data]

enum CodingKeys: String, CodingKey {
    case data = "Data"
    case Success, ErrorMessage
}
init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.data= try container.decode([Datas].self, forKey: .data)
    self.Success = try container.decode(Bool.self, forKey: .Success)
    self.ErrorMessage = try container.decode(String?.self, forKey: .ErrorMessage)
}

struct Data: Decodable{
    let `Type`: Int
    let  Id, PatientId : Int64
    let Form,Time: String
    enum CodingKeys: String, CodingKey {
        case Id, PatientId, Form,`Type`,Time
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.PatientId = try container.decode(Int64.self, forKey: .PatientId)
        self.Id = try container.decode(Int64.self, forKey: .Id)
        self.Form = try container.decode(String.self, forKey: .Form)
        self.Time = try container.decode(String.self, forKey: .Time)
        self.`Type` = try container.decode(Int.self, forKey: .`Type`)
     }
 }

}

Then you can decode JSON with:

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let response = try decoder.decode(Response.self, from: data)
print(response.data)

The output when I use this method is as follows:

[]

I have looked at Apple's Documentation on decoding nested structs, but I still do not understand how to do the different levels of the JSON properly.

---My other method for this problem:

let task = URLSession.shared.dataTask(with: request as URLRequest)
    {(data,response,error) -> Void in
        if error != nil
        {
            print(error?.localizedDescription as Any)
            return
        }
        do
        {
            guard error == nil else {
                return
            }

            guard let data = data else {
                return
            }

            //create json object from data
            if let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary {
                    print(json)
                    if let success = json["Success"] as? Bool {
                        self.sucBool = success as! Bool
                        if let array: NSArray = json["Data"]! as? NSArray{
                            for obj in array {
                                if let dict = obj as? NSDictionary {
                                    // Now reference the data you need using:
                                    let form= dict.value(forKey: "Form")
                                }
                            }
                        }
                    }
            }
            completionHandler(self.sucBool,nil)
        }
        catch let error as NSError
        {
            print(error.localizedDescription)
            completionHandler(false,error)
        }
    }
    task.resume()

The output when I use this method is as follows:

{
Data =     (
);
ErrorMessage = "<null>";
Success = 1;

}

I can read web service response correctly but casting is false for Data. I thing there is a problem with this line of code about casting:

 if let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary

---Also, both methods do not write an error message.

Upvotes: 0

Views: 116

Answers (2)

byaruhaf
byaruhaf

Reputation: 4743

The problem is the JSON data is not valid JSON

lexical error: invalid character inside string.
          -11-2019\",\"Hour\":\"08:31\",         "Type": 8,         "T
                     (right here) ------^

Tried to correct the error with the JSON data below:

{
    "Data": [{
        "Id": 181670,
        "PatientId": 10086,
        "Form": "{\"Day\":\"14-11-2019\",\"Hour\":\"08:31\"}",
        "Type": 8,
        "Time": "2019-11-14T08:31:00"
    }],
    "Success": true,
    "ErrorMessage": null
}

Upvotes: 0

RedX
RedX

Reputation: 501

  1. Check your JSON on JSONlint.com as @Yvonne Aburrow mentioned
  2. Refactor your structs. You can write them a lot easier! Example:
struct SomeRoot: Decodable {
    let data: [Data]
    let success: Bool
    let errorMessage: String?
}

struct Data: Decodable {
    let id: Int
    let patientId: Int
    let form: String
    let type: Int
    let time: String
}
do {
    let myFetchedJSON = try JSONDecoder().decode(SomeRoot.self, from: jsonObject!)
    print(myFetchedJSON.data)
} catch {
    print(error.localizedDescription)
}

...some hints:

  • For decoding json the Decodable protocol is enough. The Codable protocol you used is for encoding & decoding.
  • you need to do/catch the try JSONDecoder().deco[...] block. If you print the error in the catch {} block you'll find out what is going wrong

Upvotes: 1

Related Questions