ASN ASN - 4 days ago 6
JSON Question

Deserialize a Dictionary (JSON) to a swift object

I'm trying to build a login function (POST method) and the resultant is a JSON with user details and few other details. I have created a class with all the fields I need to use from the result of POST call. But I'm facing an issue with deserialzing the json to the object of the class. Can some one help me with this. (I have seen similar questions on SO and tried solving using the solution. I have tried converting the json to string and then to swift object using

var UserDetails = UserDetails(json:jsonString)

)

My code:

class UserDetails {
let token:String
let agent_id: Int
let user_id:Int
let company_id:Int
let affliate_Id:Int
let role_id:Int
let username: String
let surname:String
let lastname:String

init(token:String,agent_id: Int,user_id:Int,company_id:Int,affliate_Id:Int,role_id:Int,username: String,surname:String,lastname:String) {
self.token = token;
self.agent_id = agent_id;
self.user_id = user_id;
self.company_id = company_id;
self.affliate_Id = affliate_Id;
self.role_id = role_id;
self.username = username;
self.surname = surname;
self.lastname = lastname;
} }


My controller class:

let task = session.dataTask(with: request as URLRequest) { data, response, error in
guard data != nil else {
print("no data found: \(error)")
return
}

do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
NSLog("Login SUCCESS");
let prefs:UserDefaults = UserDefaults.standard
prefs.set(username, forKey: "USERNAME")
prefs.set(udid, forKey: "UDID")
prefs.synchronize()
print("Response: \(json)")

//var jsonString = NSString(data: json, encoding: String.Encoding.utf8)! as String
//when I tried to do the above statement, an error is thrown. Cannot convert value of type NSDictionary to expected argument type Data
//var person:UserDetails = UserDetails(json: jsonString)

self.dismiss(animated: true, completion: nil)
} else {
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)// No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError)// Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Error could not parse JSON: '\(jsonStr)'")
}
}

task.resume()


JSON Response:

{
"user": {
"token": "ABCDEFGHI",
"agent_id": 0,
"user_id": 151,
"company_id": 1,
"affiliate_Id": 0,
"role_id": 1,
"username": "testman1",
"surname": "Test",
"lastname": "man",
},
"menu": [
{ .....


Can someone help me in solving this. Tia

Answer

You should avoid using Foundation classes (NSDictionary etc) and use Swift types.

I also suggest you add a failable initialiser to your UserDetails class that accepts a dictionary:

class UserDetails {
    let token: String
    let agentId: Int
    let userId: Int
    let companyId: Int
    let affliateId: Int
    let roleId: Int
    let username: String
    let surname: String
    let lastname: String

    init?(dictionary: [String:Any]) {

        guard let token = dictionary["token"] as? String,
            let agentId = dictionary["agent_id"] as? Int,
            let userId = dictionary["user_id"] as? Int,
            ...  // And so on 
        else {
            return nil
        }

        self.token = token;
        self.agentId = agentId;
        self.userId = userId;
        self.companyId = companyId;
        self.affliateId = affliateId;
        self.roleId = roleId;
        self.username = username;
        self.surname = surname;
        self.lastname = lastname;
    } 
}

and in your completion block:

 do {
     if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any] {

         if let userDict = json["user"] as [String:Any] {
              guard let userObject = UserDetails(dictionary:userDict) else {
                  print("Failed to create user from dictionary")
                  return
              }
              // Do something with userObject
         }
     }

  } catch let parseError {

I also took the liberty of removing the _ from your properties because _ are icky

Comments