如何在 Swift 4 中为 JSON 编写可解码,其中键是动态的?

Posted

技术标签:

【中文标题】如何在 Swift 4 中为 JSON 编写可解码,其中键是动态的?【英文标题】:How to write a Decodable for a JSON in Swift 4, where keys are dynamic? 【发布时间】:2018-02-17 02:35:09 【问题描述】:

我有一个这样的 JSON。

我需要使用 Swift 4 在我的 ios 应用中创建一个对应的 Decodable 结构。


    "cherry": 
        "filling": "cherries and love",
        "goodWithIceCream": true,
        "madeBy": "my grandmother"
     ,
     "odd": 
         "filling": "rocks, I think?",
         "goodWithIceCream": false,
         "madeBy": "a child, maybe?"
     ,
     "super-chocolate": 
         "flavor": "german chocolate with chocolate shavings",
         "forABirthday": false,
         "madeBy": "the charming bakery up the street"
     

在制作可解码结构方面需要帮助。如何提及 cherryoddsuper-chocolate 等未知键。

【问题讨论】:

您希望cherryoddsuper-chocolate 在结构中如何表示? 您是否必须基本上使用 Swift JSON API,或者您是否也愿意使用 JSONModel 之类的东西? @AndréSlotta 我需要将这些标题(樱桃、奇数、超级巧克力)放在一个数组中。 @prabodhprakash 我应该使用 Swift 的 JSON API。 没有本地方法可以做到这一点。图书馆可以帮助您做到这一点。 【参考方案1】:

您需要在定义CodingKeys 时发挥创意。我们将响应称为FoodList 和内部结构FoodDetail。你还没有定义FoodDetail 的属性,所以我假设这些键都是可选的。

struct FoodDetail: Decodable 
    var name: String!
    var filling: String?
    var goodWithIceCream: Bool?
    var madeBy: String?
    var flavor: String?
    var forABirthday: Bool?

    enum CodingKeys: String, CodingKey 
        case filling, goodWithIceCream, madeBy, flavor, forABirthday
    


struct FoodList: Decodable 
    var foodNames: [String]
    var foodDetails: [FoodDetail]

    // This is a dummy struct as we only use it to satisfy the container(keyedBy: ) function
    private struct CodingKeys: CodingKey 
        var intValue: Int?
        var stringValue: String

        init?(intValue: Int)  self.intValue = intValue; self.stringValue = "" 
        init?(stringValue: String)  self.stringValue = stringValue 
    

    init(from decoder: Decoder) throws 
        self.foodNames = [String]()
        self.foodDetails = [FoodDetail]()

        let container = try decoder.container(keyedBy: CodingKeys.self)
        for key in container.allKeys 
            let foodName = key.stringValue
            var foodDetail = try container.decode(FoodDetail.self, forKey: key)
            foodDetail.name = foodName

            self.foodNames.append(foodName)
            self.foodDetails.append(foodDetail)
        
    



// Usage
let list = try! JSONDecoder().decode(FoodList.self, from: jsonData)

【讨论】:

你能告诉我如何用这种方法实现可编码协议吗? 没关系,我找到了一个解释所有关于 json 解码和编码的网站。 benscheirman.com/2017/06/… 但是如何/在哪里将 foodName 与 FoodDetail 对象相关联? @vikzilla 好问题。 OP 不清楚应该如何定义 FoodDetail,所以我错过了这个名字。查看编辑后的答案

以上是关于如何在 Swift 4 中为 JSON 编写可解码,其中键是动态的?的主要内容,如果未能解决你的问题,请参考以下文章

带有可配置键的 Swift 4 JSON 解码

如何在 Swift 4 的可解码协议中使用自定义键?

使用可选值 Swift 4 解码嵌套 JSON

Swift 4 解码简单的根级 json 值

Swift 4 可解码 - 附加变量

如何在 Swift 4 中解码 JSON(JSON Web 令牌)?