Decode json output to a model

2019-06-12 04:02发布

I have this json output that I want to parse using Codable:

{
"success": true,
"total": 1,
"users": [
    {
        "user": {
            "id": "1",
            "fname": "admin",
            "lname": "admin",
            "login": "admin",
            "actif": "0",
            "last_connection_date": "2018-01-18 16:02:34"
        }
    }
],
"msg": ""
}

And I just want to exctact the user's informations out of it. My user's model

import RealmSwift

class User: Object, Codable {

@objc dynamic var id: String = ""
@objc dynamic var fname: String = ""
@objc dynamic var lname: String = ""
@objc dynamic var login: String = ""

//    private enum CodingKeys : String, CodingKey {
//        case id = "users[0].user.id"
//        case fname = "users[0].user.fname"
//        case lname = "users[0].lname"
//        case login = "users[0].user.login"
//        case password = "users[0].user.password"
//    }

}

// Somewhere in my code
Alamofire.request(Path.userInformations(id: userId).rawValue).
responseJSON(completionHandler: { response in
       do {
            let user = try JSONDecoder().decode(User.self, from: response.data!)
            } catch (let error) {
                print(error.localizedDescription)
            }
       })

I've tried extracting the user's object, but wasn't successful casting it to Data to feed it to JSONDecoder().decode() method.

Responding to Vishal16 's comment

I've tried you first approach. It does not seem to work because, I think, of keyword "user" before the user's object. I've tried adding a new struct that wrap the user's object, but does not solve it.

struct ResponseBody : Codable {
   var success : Bool?
   var total : Int?
   var users : [UserHolder]?
   var msg : String?
   var query_start : String?
   var query_end : String?
   var query_time : String?
   var paging : Bool?
}

struct UserHolder : Codable {
    var user: User?

    enum CodingKeys: String, CodingKey {

        case user = "user"

    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        user = try values.decodeIfPresent(User.self, forKey: .user)
    }
}

2条回答
姐就是有狂的资本
2楼-- · 2019-06-12 04:25
class User: Object, Codable {

@objc dynamic var id: String = ""
@objc dynamic var fname: String = ""
@objc dynamic var lname: String = ""
@objc dynamic var login: String = ""

}

class Users: Object, Codable {

@objc dynamic var users: [User]

}

And for decoding

let user = try JSONDecoder().decode(Users.self, from: response.data!)

I think it should resolve the issue.

The other way is, you have to convert your response.data to Dictionary to dig down to user object.

查看更多
我只想做你的唯一
3楼-- · 2019-06-12 04:49

I think your response class structure should be like:

import Foundation
struct ResponseBody : Codable {
var status : Bool?
var total : Int?
var users : [User]? //list of users 
var msg : String?

enum CodingKeys: String, CodingKey {

    case status = "status"
    case total = "total"
    case users = "users"
    case msg = "msg"
}

init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    status = try values.decodeIfPresent(Bool.self, forKey: . status)
    total = try values.decodeIfPresent(Int.self, forKey: . total)
    users = try values.decodeIfPresent([User].self, forKey: . users)
    msg = try values.decodeIfPresent(String.self, forKey: . msg)
}
}

Now you will able to retrive your JSON data to object

let jsonDecoder = JSONDecoder()
let response = try jsonDecoder.decode(ResponseBody.self, from: data)

for user in response.users {
   // user object is here
}

#edit

If you do not want to parse full response to JSON object

  1. First convert Data to JSON Object using

    let jsonResponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! Dictionary

  2. Get users list string JSON then convert it to Data and after that data to User List object

    if let responseBody = jsonResponse["users"] {

    let dataBody = (responseBody as! String).data(using: .utf8)! if let obj = Utils.convertToArray(data: dataBody) { print(obj) // list of user obj } }

Hear is the method using in above implementation

class func convertToArray(data: Data) -> [AnyObject]? {
    do {
        return try JSONSerialization.jsonObject(with: data, options: []) as? [AnyObject]
    } catch {
        Constants.print(items: error.localizedDescription)
    }
    return nil
}

Hope this help you. Happy codding :)

So hear is the working code for you It's just working fine in my Playground. Please see below screenshots

1.enter image description here

2.enter image description here

3.enter image description here

Decode json output to a model

enter image description here

Result:

enter image description here

查看更多
登录 后发表回答