Как я могу сделать Декодируемый объект из словаря? - PullRequest
0 голосов
/ 20 декабря 2018

Я хочу иметь структуру, которую можно создать с помощью обычного протокола Codable или словаря (существующий код требует создания экземпляра словаря).

У меня есть этот код на игровой площадке, но я не уверен, чтосделать в моем втором init, который принимает словарь.Как сделать объект декодера из словаря?

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
...

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Расширьте свой протокол Parsable для автоматического создания искомого инициализатора.

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)
    }
}
0 голосов
/ 20 декабря 2018

Вы на правильном пути.

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)

Все, что я сделал, было:

  1. создание объекта JSONdecoder.
  2. использование этого JSONdecoder для декодированияобъект типа ResponseModel
  3. присваивает результат декодирования self.Таким образом, все свойства self назначаются.
...