Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Codable - decode nested dictionary

Lets say I have a dictionary like this:

{"user_data":{"id":3,"name":"Damian D","email":"[email protected]"},"status":true}

How can I use Codable protocol to decode just user_data into such struct:

struct User: Codable {
    private enum CodingKeys: String, CodingKey {
        case id
        case username = "name"
        case email
    }

    let id:       Int
    let username: String
    let email:    String
}

Do I need to convert this sub dictionary into Data, or is there a easier way?

like image 583
Damian Dudycz Avatar asked Dec 07 '22 16:12

Damian Dudycz


2 Answers

If you create nested Coding Keys you will accomplish decoding the response using only one data model.

Given the following JSON response:

let data = """
{
    "user_data": {
        "id":3,
        "name":"Damian D",
        "email":"[email protected]"

    },
    "status":true
}
""".data(using: .utf8, allowLossyConversion: false)!

and the following data model:

public struct User: Decodable {

    var id: Int
    var name: String
    var email: String

    // MARK: - Codable
    private enum RootCodingKeys: String, CodingKey {

        case userData = "user_data"

        enum NestedCodingKeys: String, CodingKey {
            case id
            case name
            case email
        }
    }

    required public init(from decoder: Decoder) throws {

        let rootContainer = try decoder.container(keyedBy: RootCodingKeys.self)
        let userDataContainer = try rootContainer.nestedContainer(keyedBy: RootCodingKeys.NestedCodingKeys.self, forKey: .userData)

        self.id = try userDataContainer.decode(Int.self, forKey: .id)
        self.name = try userDataContainer.decode(String.self, forKey: .name)
        self.email = try userDataContainer.decode(String.self, forKey: .email)
    }
}

You can decode your response into a single object:

let decoder = JSONDecoder()
let user = try? decoder.decode(User.self, from: data)
like image 82
Mike Velu Avatar answered Dec 25 '22 16:12

Mike Velu


Create a new struct that has a userData member of type User.

struct Response: Codable {
    private enum CodingKeys: String, CodingKey {
        case userData = "user_data"
        case status
    }

    let userData: User
    let status:   Bool
}
like image 21
theMikeSwan Avatar answered Dec 25 '22 14:12

theMikeSwan