Getting error in json decode

Hi there, i am new to mac os application development. Actually i am trying to decode one json object but getting error " Type Missmatch" i do not know how to create a proper structure for parsing json. I have following codes:-


JSON FROM SERVER:

--------------------------


{
    "message": "Student Found",
    "student": {
        "studentID": "ST000000195",
        "name": "RAVI VARMA",
        "phone": "7873500016",
        "email": "ravi@gmail.com",
        "specialisation": "SP002",
        "yearOfJoining": "2015",
        "keyCode": "1111111111",
        "schoolID": "BS00001",
        "registrationID": "UNOX001",
        "batchID": "BA000000001",
        "usingOS": "Windows",
        "loginID": "LU000000317",
        "course": "CO0000001",
        "macID": "0.0.0.0",
        "bulkUpload": null,
        "createdBy": "LU000000011",
        "createdOn": "2018-08-07T12:08:55",
        "updatedBy": "LU000000011",
        "updatedOn": "2018-08-14T00:00:00",
        "address": "KARNOOL, AP",
        "gender": "Female",
        "status": 1
    }
}


Serialization

    if let responseJSON = try JSONSerialization.jsonObject(with: data!) as? [String:AnyObject]{
                    if(responseJSON.count == 2){
                        self.parseJSON(data: data!)


My structure

struct StudentLogin: Decodable
    {
        
        struct StudentLoginMessage{
            public var message:String
        }
        struct StudentLoginData{
            public var studentID:String
            public var name:String
            public var phone:String
            public var email:String
            public var specialisation:String
            public var yearOfJoining:String
            public var keyCode:String
            public var schoolID:String
            public var registrationID:String
            public var batchID:String
            public var usingOS:String
            public var loginID:String
            public var course:String
            public var macID:String
            public var bulkUpload:String
            public var createdBy:String
            public var createdOn:Date
            public var updatedBy:String
            public var updatedOn:Date
            public var address:String
            public var gender:String
            public var status:String
        }
    }
    
    var studentdata = [StudentLogin]()


I am trying to do like this

func parseJSON(data: Data){
        do {
            let decoder = JSONDecoder()
            self.studentdata = try decoder.decode([StudentLogin].self, from: data)
        } catch let error {
            print(error as? Any)
        }
    }


Can anyone suggest me the proper way to parse the json correctly please.

Accepted Reply

First of all, your JSON FROM SERVER represents a single JSON object, which is outlined as follows:


{
    "message": "Student Found",
    "student": {
        ...
    }
}


It has two key-value pairs, one "message" with a JSON string, another "student" with a JSON object.


If you want to represent it as a Decodable Swift struct, you need two properties, but your `StudentLogin` has no properties.

You may need something like this:

struct StudentLogin: Decodable {
    var message: String
    var student: Student
}


With Student defined as:

struct Student: Decodable {
    var studentID: String
    var name: String
    var phone: String
    var email: String
    var specialisation: String
    var yearOfJoining: String
    var keyCode: String
    var schoolID: String
    var registrationID: String
    var batchID: String
    var usingOS: String
    var loginID: String
    var course: String
    var macID: String
    var bulkUpload: String? //<- can be null
    var createdBy: String
    var createdOn: Date
    var updatedBy: String
    var updatedOn: Date
    var address: String
    var gender: String
    var status: Int //<- JSON number
}


Better modify your deserializing code like this to clarify what may cause problem:

        do {
            guard let data = data else {
                print("data is nil")
                return
            }
            let responseJSON = try JSONSerialization.jsonObject(with: data)
            if let response = responseJSON as? [String: Any], response.count == 2 {
                self.parseJSON(data: data)
                print(self.studentdata)
            } else {
                print("response was not a JSON object")
                //...
            }
        } catch {
            print(error)
            //...
        }


The response is not a JSON array, so the result type should not be an Array type like `[StudentLogin]`.

And the date format in you JSON cannot be recognized as `Date` with `JSONDecoder`.

So your `parseJSON` would look like this:

    var studentdata: [StudentLogin] = [] //<- I guessed your `studentdata` is an Array of `StudentLogin`
    func parseJSON(data: Data) {
        do {
            let decoder = JSONDecoder()
            let dateFormatter = DateFormatter()
            dateFormatter.timeZone = TimeZone.current //<- You may need to change this
            dateFormatter.locale = Locale(identifier: "en_US_POSIX")
            dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
            decoder.dateDecodingStrategy = .formatted(dateFormatter)
            let studentFound = try decoder.decode(StudentLogin.self, from: data) //<- Not `[StudentLogin].self`
            self.studentdata = [studentFound]
        } catch let error {
            print(error)
        }
    }


The code above would not work becaused I needed to fill many parts by guess. You should better include all relevant info and error messages.

Replies

First of all, your JSON FROM SERVER represents a single JSON object, which is outlined as follows:


{
    "message": "Student Found",
    "student": {
        ...
    }
}


It has two key-value pairs, one "message" with a JSON string, another "student" with a JSON object.


If you want to represent it as a Decodable Swift struct, you need two properties, but your `StudentLogin` has no properties.

You may need something like this:

struct StudentLogin: Decodable {
    var message: String
    var student: Student
}


With Student defined as:

struct Student: Decodable {
    var studentID: String
    var name: String
    var phone: String
    var email: String
    var specialisation: String
    var yearOfJoining: String
    var keyCode: String
    var schoolID: String
    var registrationID: String
    var batchID: String
    var usingOS: String
    var loginID: String
    var course: String
    var macID: String
    var bulkUpload: String? //<- can be null
    var createdBy: String
    var createdOn: Date
    var updatedBy: String
    var updatedOn: Date
    var address: String
    var gender: String
    var status: Int //<- JSON number
}


Better modify your deserializing code like this to clarify what may cause problem:

        do {
            guard let data = data else {
                print("data is nil")
                return
            }
            let responseJSON = try JSONSerialization.jsonObject(with: data)
            if let response = responseJSON as? [String: Any], response.count == 2 {
                self.parseJSON(data: data)
                print(self.studentdata)
            } else {
                print("response was not a JSON object")
                //...
            }
        } catch {
            print(error)
            //...
        }


The response is not a JSON array, so the result type should not be an Array type like `[StudentLogin]`.

And the date format in you JSON cannot be recognized as `Date` with `JSONDecoder`.

So your `parseJSON` would look like this:

    var studentdata: [StudentLogin] = [] //<- I guessed your `studentdata` is an Array of `StudentLogin`
    func parseJSON(data: Data) {
        do {
            let decoder = JSONDecoder()
            let dateFormatter = DateFormatter()
            dateFormatter.timeZone = TimeZone.current //<- You may need to change this
            dateFormatter.locale = Locale(identifier: "en_US_POSIX")
            dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
            decoder.dateDecodingStrategy = .formatted(dateFormatter)
            let studentFound = try decoder.decode(StudentLogin.self, from: data) //<- Not `[StudentLogin].self`
            self.studentdata = [studentFound]
        } catch let error {
            print(error)
        }
    }


The code above would not work becaused I needed to fill many parts by guess. You should better include all relevant info and error messages.

Thank you buddy, it worked for me 🙂

Thanks for reporting. I'm very happy to hear that.