-2

I am having problems in decoding JSON response using Swift 4 Decoding Functionality. I have main construct and it has one inner construct var hr_employees: [Employee]? = []. The problem is JSON not mapping for 'var hr_employees: [Employee]? = [].

I am getting correct values forthe three root values response_status,access_level,session_token.

////////////Code for Struct////////////////////////

struct EmployeeData: Codable {
     var response_status:Int=0
     var access_level:Int=0
     var session_token:String=""
     var hr_employees: [Employee]? = []
}

private enum CodingKeys: String, CodingKey {
        case response_status="response_status"
        case access_level="access_level"
        case session_token="session_token"
        case hr_employees="hr_employees"
    }

    init() {

    }



init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            response_status = try values.decode(Int.self, forKey: .response_status)
            do{
                session_token = try values.decode(String.self, forKey: .session_token)
            }catch {
                print( "No value associated with key title (\"session_token\").")
            }
            do{
                access_level = try values.decode(Int.self, forKey: .access_level)
            }
            catch {
                print( "No value associated with key access_level ")
            }
        }

/////////////////Inner Struct///////////////////////

  struct Employee: Codable {
        var userId:Int=0
        var nameFirst:String=""
        var nameLast:String=""
        var position:String=""
        var company:String=""
        var supervisor:String=""
        var assistant:String=""
        var phone:String=""
        var email:String=""
        var address:String=""
        var gender:String=""
        var age:Int=0
        var nationality:String=""
        var firstLanguage:String=""
        var inFieldOfView:String = "0"
        var photo:String="user-default"
        var status:String="3"
    }

////////////Following is the JSON//////////////////////

{
"response_status":1
,"access_level":2
,"hr_employees":[
{
"user_id":4226
,"name_last":"Sampe"
,"name_first":"Frederica"
,"position":"Systems Maint"
,"phone":"123456"
,"email":"omega@demo.mobile"
,"address":"00100 Helsinki 1"
,"age":67
,"company":"Omega Enterprise"
}
,{
"user_id":5656
,"name_last":"Aalto"
,"name_first":"Antero"
,"position":"Programming Methodology and Languages Researcher"
,"supervisor":"Mayo Georgia"
,"phone":"123456"
,"email":"omega@demo.mobile"
,"address":"00100 Finland "
,"age":51
,"company":"Omega Fire Related Equipment"
}
]
}
Vajahat Ali
  • 117
  • 1
  • 7

2 Answers2

1

One problem is that what is in the JSON does not match your definition of Employee. For example nameFirst is not present and name_first is.

Another is that you have a custom implementation of init(from:), and it never fetches the hr_employees value!

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

Quite a few things for you to improve on:

  1. Your Structs can be improved to harness automation capability of the Codable protocol.
  2. You need to understand why you're using a CodingKeys enum
    • and in your case... also where best to have it (hint: inside the Struct itself)
  3. You need to know which parameters need to be optional and why
    • this depends on your json structure ofcourse
  4. If the parameters are to have a default value then there's a whole different process you need to follow; like having your own init(from:Decoder)
    • which you have to a certain extent but doesn't really handle everything in it's current state

Based on your given JSON example, you can simply do the following.
However... do note that this is not designed to provide default values. i.e. If a key is missing in the json, like status for example, then the parameter status in your Employee struct will be nil rather than a default value of "3".

struct EmployeeData: Codable {
    var responseStatus: Int
    var accessLevel: Int

    /*
     sessionToken is optional because as per your JSON
     it seems it not always available
     */
    var sessionToken: String?

    var hrEmployees: [Employee]

    /*
     CodingKeys is inside the struct
     It's used if the JSON key names are different than
     the ones you plan to use.
     i.e. JSON has keys in snake_case but we want camelCase
     */
    enum CodingKeys: String, CodingKey {
        case responseStatus = "response_status"
        case accessLevel = "access_level"
        case sessionToken = "session_token"
        case hrEmployees = "hr_employees"
    }
}

struct Employee: Codable {
    var userId: Int
    var nameFirst: String
    var nameLast: String
    var position: String
    var company: String
    var supervisor: String?
    var assistant: String?
    var phone: String
    var email: String
    var address: String
    var gender: String?
    var age: Int
    var nationality: String?
    var firstLanguage: String?
    var inFieldOfView: String?
    var photo: String?
    var status: String?

    enum CodingKeys: String, CodingKey {
        case userId = "user_id"
        case nameFirst = "name_first"
        case nameLast = "name_last"
        case firstLanguage = "first_language"
        case inFieldOfView = "in_field_of_view"

        /*
         Keys names that are same in json as well as in your
         model need not have a raw string value
         but must be defined if it's to be encoded/decoded
         from the json else it can be omitted and a default
         value will be required which won't affect the encoding
         or decoding process
         */
        case position
        case company
        case supervisor
        case assistant
        case phone
        case email
        case address
        case gender
        case age
        case nationality
        case photo
        case status
    }
}

Check:

do {
    let employeeData = try JSONDecoder().decode(EmployeeData.self,
                                                from: jsonAsData)
    print(employeeData)
}
catch {
    /*
     If it comes here then debug, it's most probably nil keys
     meaning you need more optional parameters in your struct
     */
    print(error)
}

If you want default values in your Struct and the above example is a dealbreaker for you then check the following answer:

staticVoidMan
  • 19,275
  • 6
  • 69
  • 98