3 votes

Comment puis-je fabriquer un objet décodable à partir d'un dictionnaire ?

Je veux avoir une structure qui peut être instanciée via le protocole Codable normal ou un dictionnaire (le code existant nécessite l'instanciation du dictionnaire).

J'ai ce code dans un playground, mais je ne suis pas sûr de ce que je dois faire dans mon second init qui prend un Dictionnaire. Comment puis-je créer un objet Decoder à partir d'un dictionnaire ?

import Foundation

public protocol Parsable: Decodable {
    init(dict: [String: Any]) throws
}

struct LinkModel: Parsable {
    var href: String
    var text: String

    init(dict: [String: Any]) throws {
        href = "/store/options.aspx"
        text = "Buy"
    }
}

struct ResponseModel: Parsable {
    var link: LinkModel?
    let showCell: Bool

    enum CodingKeys : String, CodingKey {
        case link
        case showCell = "show"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        let linkResponses = try container.decode([LinkModel].self, forKey: .link)
        link = linkResponses.first

        showCell = try container.decode(Bool.self, forKey: .showCell)
    }

    init(dict: [String: Any]) throws {
        let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
        let decoder = ??? // what do I do here?
        self.init(from: decoder)
    }
}

let jsonText = """
{
    "show": true,
    "link": [
        {
        "text": "Buy",
        "href": "/store/options.aspx"
        }
    ]
}
"""

// test standard Decodable instantiation
let jsonData = jsonText.data(using: .utf8)!
let model = try! JSONDecoder().decode(ResponseModel.self, from: jsonData)

print(model.link?.href)

// test dictionary instantiation
...

8voto

wadda_wadda Points 515

Étendez votre Parsable pour générer automatiquement l'initialisateur que vous recherchez.

extension Parsable {
    init(dict: [String: Any]) throws {
        let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
        let decoder = JSONDecoder()
        self = try decoder.decode(Self.self, from: jsonData)
    }
}

3voto

Honey Points 9108

Vous êtes sur la bonne voie.

import Foundation

public protocol Parsable: Decodable {
    init(dict: [String: Any]) throws
}

struct LinkModel: Parsable {
    var href: String
    var text: String

    init(dict: [String: Any]) throws {
        href = "/store/options.aspx"
        text = "Buy"
    }
}

struct ResponseModel: Parsable {
    var link: LinkModel?
    let showCell: Bool

    enum CodingKeys : String, CodingKey {
        case link
        case showCell = "show"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        let linkResponses = try container.decode([LinkModel].self, forKey: .link)
        link = linkResponses.first

        showCell = try container.decode(Bool.self, forKey: .showCell)
    }

    init(dict: [String: Any]) throws {
        let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
        // 1.
        let decoder = JSONDecoder()
        // 2. 
        let result = try decoder.decode(ResponseModel.self, from: jsonData)
        // 3. 
        self = result

    }
}

let jsonText = """
{
    "show": true,
    "link": [
        {
        "text": "Buy",
        "href": "/store/options.aspx"
        }
    ]
}
"""

// test standard Decodable instantiation
let jsonData = jsonText.data(using: .utf8)!
let model = try! JSONDecoder().decode(ResponseModel.self, from: jsonData)

print(model.link?.href)

Tout ce que j'ai fait, c'est :

  1. créer un objet JSONdecoder.
  2. utiliser ce JSONdecoder pour décoder un objet de type ResponseModel
  3. affecter le résultat du décodage à self . De cette façon, toutes les propriétés de self sont attribuées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X