[英]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
正在解碼一個需要String
或JMAPMethodResponse
的數組。 該數組如下所示:
[
"Mailbox/get",
{
"state": "92",
"accountId": "xyz"
},
"0"
]
它實際上包含一個String
或JMAPMailboxList
(不是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.