如何从字典制作可分解对象?

时间:2018-12-20 17:23:54

标签: swift decoding

我希望有一个可以通过常规Codable协议或字典实例化的Struct(现有代码需要字典实例化)。

我在操场上有此代码,但是我不确定在第二个需要Dictionary的init中该怎么做。如何用字典制作Decoder对象?

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 :(得分:1)

扩展您的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)
    }
}

答案 1 :(得分:0)

您在正确的道路上。

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的所有属性。