How to parse a JSON containing dynamic keys using decodable?

时间:2018-10-24 11:25:36

标签: ios swift decodable

The problem

I am currently experiencing issues with decoding generic keys in a JSON. My current implementation accepts 3 keys primary, secondary, tertiary. However in the future I want to have the key of JSON dictionaries to be generic. I have tried to implement a similar way as stated in this tutorial: https://benscheirman.com/2017/06/swift-json/. Unfortunately I can not get it working and some help is really welcome.

My question ain't no duplicate of the below one

The following post handles a way different level of generic"nes": How to deal with completely dynamic JSON responses therefore my question is a lot more concise than the one that market this question as duplicate with the post above..

current JSON

{
  "primary": {
    "color": [3,111,66,1],
    "font": {
      "name": "UniversLTStd-UltraCn",
      "size": "16"
    }
  },
  "secondary": {
    "color": [11,34,56,1],
    "font": {
      "name": "UniversLTStd-UltraCn",
      "size": "16"
    }
  },
  "tertiary": {
    "color": [233,222,211,1],
    "font": {
      "name": "UniversLTStd-UltraCn",
      "size": "16"
    }
  }
}

wished / possible JSON

{
      "SomeKey": {
        "color": [3,111,66,1],
        "font": {
          "name": "UniversLTStd-UltraCn",
          "size": "16"
        }
      },
      "OtherKey": {
        "color": [11,34,56,1],
        "font": {
          "name": "UniversLTStd-UltraCn",
          "size": "16"
        }
      },
      "AnotherKey": {
        "color": [233,222,211,1],
        "font": {
          "name": "UniversLTStd-UltraCn",
          "size": "16"
        }
      }
    }

The decodable structs can be found here: https://pastebin.com/ZYafkDNH

The question

How can I migrate my current code to accepts dynamic keys (at the place of primary, secondary, tertiary..) so I do not have to hard code them in the Base/Root Struct which can be found in Theme now.

2 个答案:

答案 0 :(得分:2)

您可以尝试将其解析为[String:Key]的字典,而不是对键进行硬编码,因为如果更改了键,它将被解析,但是您必须在应用程序内部做一些逻辑才能知道哪个值对应于指定的键

let res = try? JSONDecoder().decode([String:Key].self, from: jsonData)


struct Key: Codable {
    let color: [Int]
    let font: Font
}

struct Font: Codable {
    let name, size: String
}

答案 1 :(得分:1)

您似乎负责JSON,因此我建议将结构更改为数组和type属性。

[{"type": "primary",
  "appearance": {
    "color": [3,111,66,1],
    "font": {
      "name": "UniversLTStd-UltraCn",
      "size": "16"
      }
    }
  },
  {
  "type": "secondary",
  "appearance": {
    "color": [11,34,56,1],
    "font": {
      "name": "UniversLTStd-UltraCn",
      "size": "16"
      }
    }
  },
  {
  "type": "tertiary",
  "appearance": {
    "color": [233,222,211,1],
    "font": {
      "name": "UniversLTStd-UltraCn",
      "size": "16"
      }
    }
}]

这更容易维护。

对应的结构是

struct Theme : Decodable {
    let type : String // could be even a custom enum
    let appearance : Appearance
}

struct Appearance: Decodable {
    let color: [UInt8]
    let font: Font
}

struct Font: Decodable {
    let name, size: String
}

并将JSON解码为[Theme].self

否则,按照Sh_Khan的建议,您必须解码字典或编写自定义初始化程序。