我必須從這個 JSON 中解碼一個物件:
{
"id": "..."
"someData": { ... },
"elements": {
"values": [
{
"id": "1",
...
},
{
"id": "2"",
...
}
]
}
}
所以我有幾個這樣的結構:
struct Object: Codable {
let id: String
let someData: SomeCodableObject
let elements: Elements
}
struct Elements: Codable {
let values: [Value]
}
struct Value: Codable {
let id: String
...
}
在用一些資料填充每個元素后,我必須發送一個類似于解碼的物件,但分別通過“elementQuotes”和“valueQuotes”更改“元素”和“值”(是的,我知道API應該避免這種奇怪的行為,但這是不可能的......),也就是像這樣的JSON:
{
"id": "..."
"someData": { ... },
"elementQuotes": {
"valueQuotes": [
{
"id": "1",
...
},
{
"id": "2"",
...
}
]
}
}
有沒有辦法在不使用不同物件的情況下實作這一點(一些用于解碼,另一些用于編碼)。也就是說,有沒有辦法為編碼/解碼指定不同的編碼鍵字串值
我再說一遍:我知道這在 API 方面是一個非常糟糕的做法,但是......我必須管理這個“功能”
uj5u.com熱心網友回復:
你可以嘗試這樣的事情(我這里只處理解碼):
extension String: Error {}
struct Object: Decodable {
let id: String
let elements: Elements
enum CodingKeys: String, CodingKey {
case id
case elements
case elementQuotes
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .id)
let elements = try container.decodeIfPresent(Elements.self, forKey: .elements)
let elementQuotes = try container.decodeIfPresent(Elements.self, forKey: .elementQuotes)
guard let realElements = elements ?? elementQuotes else { throw "Missing elements" }
self.elements = realElements
}
}
struct Elements: Decodable {
let values: [Value]
enum CodingKeys: String, CodingKey {
case values
case valueQuotes
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let values = try container.decodeIfPresent([Value].self, forKey: .values)
let valueQuotes = try container.decodeIfPresent([Value].self, forKey: .valueQuotes)
self.values = values ?? valueQuotes ?? []
}
}
struct Value: Decodable {
let id: String
}
let test1 = """
{
"id": "123",
"elements": {
"values": [
{
"id": "1"
},
{
"id": "2"
}
]
}
}
""".data(using: .utf8)!
let test2 = """
{
"id": "123",
"elementQuotes": {
"valueQuotes": [
{
"id": "1"
},
{
"id": "2"
}
]
}
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let json1 = try decoder.decode(Object.self, from: test1)
let json2 = try decoder.decode(Object.self, from: test2)
uj5u.com熱心網友回復:
您可以嘗試撰寫自定義初始化解碼器
struct Root: Decodable {
let id: String
let someData: String
let elements: Elements
enum CodingKeys: String, CodingKey {
case id, someData, elements
case elementQuotes
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
someData = try container.decode(String.self, forKey: .someData)
do {
elements = try container.decode(Elements.self, forKey: .elements)
}
catch {
elements = try container.decode(Elements.self, forKey: .elementQuotes)
}
}
}
struct Elements: Decodable {
let values: [Value]
enum CodingKeys: String, CodingKey {
case values
case valuesQuotes
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
values = try container.decode([Value].self, forKey: .values)
}
catch {
values = try container.decode([Value].self, forKey: .valuesQuotes)
}
}
}
struct Value: Codable {
let id: String
}
uj5u.com熱心網友回復:
對不同鍵進行編碼的一種簡單方法是添加自定義keyEncodingStrategy.
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .custom { keys in
switch keys.last!.stringValue {
case "elements": return AnyKey(stringValue: "elementQuotes")!
case "values": return AnyKey(stringValue: "valueQuotes")!
default: return keys.last!
}
}
這還需要一個額外的結構AnyKey
struct AnyKey: CodingKey {
var stringValue: String
var intValue: Int?
init?(stringValue: String) { self.stringValue = stringValue }
init?(intValue: Int) {
self.stringValue = String(intValue)
self.intValue = intValue
}
}
您可以在 switch 運算式中添加任意數量的案例
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/512848.html
上一篇:嵌套if與for回圈的速度
下一篇:如何快速打開應用程式位置設定?
