使用Swift解码具有不同结构的JSON

问题描述

我从nosql数据库(PK,SK,属性)获得了具有相同核心结构的json数据。根据SK的值,属性部分会有所不同。

示例:

[
  {
    "PK": "POLL#1544693DF0E88EC-3225-410E-B156-D13781B238F6","SK": "#MetaDATA#1544693DF0E88EC-3225-410E-B156-D13781B238F6","attributes": {
      "latitude": "53.34589121858683","longitude": "-6.272215191675388","max_choices": 50,"number": "1544693","poll_open": false,}
  },{
    "PK": "POLL#1544693DF0E88EC-3225-410E-B156-D13781B238F6","SK": "CHOICE#00a6ec5c-acc1-40f1-a087-31160d2cfc65","attributes": {
      "distance": 790.95097525,"latitude": 53.3416,"price": "€€","categories": [
        {
          "title": "Ramen","alias": "ramen"
        }
      ],"Vote_count": 0,"longitude": -6.26274
    }
  }
]

是否可以使用解码而不会出错?我已经坚持了几个小时。

我已经定义了以下内容

struct Result: Codable {
    var PK: String
    var SK: String
    var attributes: String
}

但是,当我解码时,出现错误

typeMismatch(Swift.String,Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0",intValue: 0),CodingKeys(stringValue: "attributes",intValue: nil)],debugDescription: "Expected to decode String but found a dictionary instead.",underlyingError: nil))

我只想将“属性”解码为通用字符串,然后在我知道如何正确处理它时根据SK的值对其进行解析。为什么这么难?

解决方法

您现在需要属性吗?还是您只是在寻找pk和sk?如果您不需要它,请不要添加

var attributes: String

在您的结构中。它不会有解码错误,并且会解码其他两个错误,只是您不会获得attribute参数。它无法解码属性 作为字符串,因为不是。它实际上更像是一本字典。除非您特别指出,否则Swift不知道如何处理。话虽这么说,您总是可以这样做

struct Result: Codable {
var PK: String
var SK: String
var attributes: Attributes
}

struct Attributes: Codable {
var lattitude: String
var longitude: String
//and whatever else you know you have
}

键仅添加您知道将包含在属性中的值,否则会给出错误

,

您需要使用JSONSerialization而不是Codable处理此问题。既然您仍然想使用相同的结构,则需要将其更改为

struct Result {
    var PK: String
    var SK: String
    var attributes: [String: Any]
}

像这样解码json

var result: Result?
do {
    if let dictionary = try JSONSerialization.jsonObject(with: data) as? [String: Any],let pk = dictionary["PK"] as? String,let sk = dictionary["SK"] as? String,let attributes = dictionary["attributes"] as? [String: Any] {
        result = Result(PK: pk,SK: sk,attributes: attributes)
    }
} catch {
    print(error)
}

现在,您仍然需要将Result的attributes([[String:Any])属性转换为更有用的功能,但这超出了这个问题