在 Swift 中使用 Codable 将 JSON 解析为对象数组而不是字典

Parse JSON as array of objects instead of dictionary using Codable in Swift

提问人:Nik 提问时间:1/28/2023 更新时间:1/29/2023 访问量:140

问:

我从 API 收到以下 JSON

{
   "someProperty":"someValue",
   "type":"type1",
   "values":{
      "first":"someValue",
      "second":"someValue" // keys and values are always different !
   }
}

我创建了模型来解析这个 JSON,它可以工作。

struct MyModel: Codable {
    let someProperty: String
    let type: SomeType
    var values: [String: String]?
}

enum SomeType: Codable {
    case type1, type2
}

但是我需要获取对象数组而不是字典。因为我需要以正确的顺序获取值。

我想要这样的东西:

struct MyModel: Codable {
    let someProperty: String
    let type: SomeType
    var values: [Value]?
}

enum SomeType: Codable {
    case type1, type2
}

struct Value: Codable {
    let key: String
    let value: String
}

而且我不明白我应该在我的代码中更改什么才能使这个模型正常工作。因为现在我收到错误“预期解码数组,但找到了字典。

有没有办法像我想要的那样解析 JSON? 有什么建议吗?也许是具有类似解析的代码示例

感谢您的时间和帮助!

JSON Swift 解析 codable 可解码

评论

0赞 Joakim Danielson 1/28/2023
和内容之间有关联吗?这些键是什么,它们仅限于一组键还是可以是任何东西?typevaluesvalues
0赞 Nik 1/28/2023
根据类型,值可以为 nil。“values”中的键可以是任何东西
0赞 burnsi 1/28/2023
似乎有一个库可以按给定的顺序解析 JSON -> github
0赞 Nik 1/28/2023
不幸的是,我不能使用库
0赞 Joakim Danielson 1/28/2023
如果输入的键可以是任何东西,那么你需要使用字典values

答:

0赞 burnsi 1/28/2023 #1

创建自定义初始化。在其中解码字典并将其映射到您的数组中:Value

struct MyModel: Codable {
    let someProperty: String
    let type: SomeType
    var values: [Value]?

    enum CodingKeys: CodingKey{
        case someProperty, type, values
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        someProperty = try container.decode(String.self, forKey: .someProperty)
        type = try container.decode(SomeType.self, forKey: .type)
        
        let dictionary = try container.decodeIfPresent([String:String].self, forKey: .values)
        values = dictionary?.map{Value(key: $0.key, value: $0.value)}
    }
}

评论

0赞 Nik 1/28/2023
谢谢,它有效!但是使用字典,我丢失了值数组中的正确顺序。有没有办法保持正确的顺序?
0赞 burnsi 1/28/2023
@Nik 否,默认情况下字典是未排序的。如果排序已知,您可以在映射后自行对它们进行排序。
0赞 Nik 1/28/2023
有没有办法只获取没有值的键数组?然后使用它们来访问字典中的值?像这样: let arrayOfKeys = try container.decodeIfPresent([String].self, forKey: .values)
0赞 burnsi 1/28/2023
@Nik 您唯一能做的就是提供自己的反序列化器。使用我在您的问题下链接的库作为基础。