簡體   English   中英

Codable Swift 具有嵌套空數組的 JSON 結構

[英]Codable Swift Structs for JSON with Nested Empty Array

我有以下 Swift 代碼和一些我正在嘗試解碼的樣本 JSON。 您可以將其放入 Playground 中親自嘗試:

let json = """
{
  "sessionState": "abc",
  "methodResponses": [
    [
      "Mailbox/get",
      {
        "state": "92",
        "accountId": "xyz"
      },
      "0"
    ]
  ]
}
"""

let data = json.data(using: .utf8)!

if let object = try? JSONDecoder().decode(JMAPResponse.self, from: data) {
  print(object)
}else{
  print("JMAP decode failed")
}

我不知道如何處理嵌套數組,所以我使用了 quicktype.io ,但它生成的內容仍然不起作用。

這是我的嵌套數組的根元素:

//Root
struct JMAPResponse: Codable{
  var sessionState: String?
  var methodResponses: [[JMAPResponseChild]]
}

這是 QuickType 建議我用來處理methodResponse節點的enum

//Nested array wrapper
enum JMAPResponseChild: Codable{
  case methodResponseClass(JMAPMethodResponse)
  case string(String)

  init(from decoder: Decoder) throws {
      let container = try decoder.singleValueContainer()
      if let x = try? container.decode(String.self) {
        self = .string(x)
        return
      }
      if let x = try? container.decode(JMAPMethodResponse.self) {
        self = .methodResponseClass(x)
        return
      }
      throw DecodingError.typeMismatch(JMAPResponseChild.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JMAPResponseChild"))
  }

  func encode(to encoder: Encoder) throws {
    var container = encoder.singleValueContainer()
    switch self {
    case .methodResponseClass(let x):
        try container.encode(x)
    case .string(let x):
        try container.encode(x)
    }
  }
}

這是下一層:

//No-key data structure (Mailbox/get, {}, 0)
struct JMAPMethodResponse: Codable{
  var method: String
  var data: [JMAPMailboxList]
  var id: String 

  func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(method)
    try container.encode(data)
    try container.encode(id)
  }
}

最后,最低級別的節點:

struct JMAPMailboxList: Codable{
  var state: String?
  var accountId: String?
}

它仍然無法成功解碼結構。 誰能看到我做錯了什么?

您的JMAPResponseChild正在解碼一個需要StringJMAPMethodResponse的數組。 該數組如下所示:

    [
      "Mailbox/get",
      {
        "state": "92",
        "accountId": "xyz"
      },
      "0"
    ]

它實際上包含一個StringJMAPMailboxList (不是JMAPMethodResponse )。 如果將JMAPMailboxList中的所有JMAPMethodResponse引用更改為JMAPResponseChild ,它應該可以工作。 您將必須進行一些后處理或更改代碼以將三個值的數組轉換為JMAPMethodResponse

您可以像這樣構建JMapMethodResponse

struct JMAPMethodResponse: Codable {
  var method: String
  var data: JMAPMailboxList
  var id: String

  init(from decoder: Decoder) throws {
    let container = try decoder.singleValueContainer()
    let values = try container.decode([JMAPResponseChild].self)

    guard case .string(let extractedMethod) = values[0] else {
      throw DecodingError.typeMismatch(String.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "First array element not String"))
    }
    method = extractedMethod
    guard case .methodResponseClass(let extractedData) = values[1] else {
      throw DecodingError.typeMismatch(JMAPMailboxList.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Second array element not JMAPMailboxList"))
    }
    data = extractedData
    guard case .string(let extractedId) = values[2] else {
      throw DecodingError.typeMismatch(String.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Third array element not String"))
    }
    id = extractedId
  }

  func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(JMAPResponseChild.string(method))
    try container.encode(JMAPResponseChild.methodResponseClass(data))
    try container.encode(JMAPResponseChild.string(id))
  }
}

然后你可以在你的回復中得到一個數組:

struct JMAPResponse: Codable{
  var sessionState: String?
  var methodResponses: [JMAPMethodResponse]
}

我不知道編碼器或解碼器是否保證數組中的順序。 如果他們不這樣做,這可能會隨機中斷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM