我正在使用第三方 API 來獲取資料。這是一個相當復雜的有效載荷,但我在一次回傳時遇到了問題。對于這個例子,我過度簡化了結構。這個結構實際上有 53 個條目,其中 34 個是結構本身。
struct MlsItemData: Codable, Hashable {
let mls_id: String
let photos: [MlsItemPhoto]?
let features: [MlsItemFeature]?
let address: MlsItemAddress
let move_in_date: String?
let stories: Int?
let client_flags: MlsItemClientFlags?
let tax_history: [MlsItemTaxHistory]? <-- our propblem child
let new_construction: Bool?
let primary: Bool?
let prop_common: MlsItemPropertyCommon?
這個 API 的結果中有一大堆其他資料物件,但我只關注一個帶有標簽 tax_history 的專案。當有資料要共享時,密鑰包含一個如下所示的陣列。
{
"tax_history": [
{
"assessment": {
"building": null,
"total": 3900,
"land": null
},
"tax": 683,
"year": "2020"
},
{
"assessment": {
"building": null,
"total": 4093,
"land": null
},
"tax": 698,
"year": 2019
}
]
}
當 API 沒有資料可以共享時,我期待:
"tax_history": [ ]
or
"tax_history": null
或者根本不在有效載荷中。但是 API 正在發送:
"tax_history": { }
I'm having difficulty as to how to deal with this in the decoder. Obviously, the built in decoder returns the "Expected to decode Array but found a dictionary instead", but is there a simple way to write a custom decoder for "just" the tax_history key and how would it be written for either getting an Array or an empty dictionary?
uj5u.com熱心網友回復:
是的,可以使用JSONDecoder. 一種方法是使用自定義型別來表示空或非空場景,并實作自定義初始化函式并嘗試解碼這兩種情況以查看哪種情況有效:
struct TaxHistoryItem: Decodable {
let year: String
// ...
}
enum TaxHistory: Decodable {
case empty
case items([TaxHistoryItem])
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let items = try? container.decode([TaxHistoryItem].self) {
self = .items(items)
} else {
struct EmptyObject: Decodable {}
// Ignore the result. We just want to verify that the empty object exists
// and doesn't throw an error here.
try container.decode(EmptyObject.self)
self = .empty
}
}
}
uj5u.com熱心網友回復:
你可以創建一個特定的型別來保存這個陣列,然后init(from:)為它撰寫一個自定義。
在初始化中,我們嘗試將 json 解碼為陣列,如果失敗,我們只需為屬性分配一個空陣列(可選屬性的 nil 是另一種可能的解決方案,但我更喜歡在 nil 之前使用空集合)
struct TaxHistoryList: Codable {
let history: [TaxHistory]
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let list = try? container.decode([TaxHistory].self) {
history = list
} else {
history = []
}
}
}
struct TaxHistory: Codable {
let tax: Int
let year: String
// other stuff
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/426821.html
