提问人:diclonius9 提问时间:10/24/2023 最后编辑:Dávid Pásztordiclonius9 更新时间:10/25/2023 访问量:49
JSONEncoder() 按不同类型对同一键进行编码 (Swift)
JSONEncoder() encoding of the same key by different types (Swift)
问:
我有一个无法克服的问题,即如何使用 JSONEncoder() 对服务器请求的有效负载进行编码。该对象应如下所示:
{
"filter": {
"conditions": [
{"key": "id_wbs", "values": [1293548]},
{"key": "id_object", "values": []},
{"key": "id", "values": [""]},
{"key": "period", "values": ["month"]},
{"key": "type_chart", "values": [""]},
{"key": "tzr_type", "values": ["monthly"]},
{"key": "type_of_work", "values": []},
{"key": "id_group_object", "values": []},
{"key": "report_date", "values": [],
"value_derived": {
"columns": "max_report_date",
"bo_id": 100006,
"filter": {
"conditions": [{"key": "id_wbs", "values": [1293548]}, {"key": "operation", "values": [""]}]
}
}
}]
},
}
问题出在“值”键上。根据键的值,它们可以是整数数组、字符串数组或日期数组。坦率地说,我对此感到困惑,现在陷入了僵局。我将不胜感激任何帮助
初步数据模型如下所示:
struct CSITableRequest: Encodable {
let filter: TableFilter
}
struct TableFilter: Encodable {
let conditions: [TableFilterConditionItem]
}
struct TableFilterConditionItem: Encodable {
let key: TableFilterConditionKey
let values: [String] //[Int]; [Date] - This is a problematic key, which can be either an Int array, a String array, or a Date array
let value_derived: TableValueDerived?
}
enum TableFilterConditionKey: String, Encodable {
case id_wbs
case id_object
case id
case period
case type_chart
case tzr_type
case type_of_work
case id_group_object
case report_date
case operation
}
struct TableValueDerived: Encodable {
let columns: String
let bo_id: Int
let filter: TableFilter
}
答:
2赞
Sweeper
10/24/2023
#1
您可以创建一个具有关联值的枚举来表示“字符串数组或 int 数组或日期数组”的概念。通过将调用委托给 // 方法来符合此类型。Encodable
encode
[Int]
[String]
[Date]
enum FilterValues: Encodable {
case strings([String])
case ints([Int])
case dates([Date])
func encode(to encoder: Encoder) throws {
switch self {
case .strings(let strings):
try strings.encode(to: encoder)
case .ints(let ints):
try ints.encode(to: encoder)
case .dates(let dates):
try dates.encode(to: encoder)
}
}
}
let values: FilterValues
2赞
Rob Napier
10/25/2023
#2
@Sweeper 的答案非常灵活,可能是理想的,但假设每个键的值都有特定的类型,我更愿意让整个事情的类型更加安全。这可能会使编写起来稍微乏味一些,但代码并不困难。
不是键和值,而是将它们放在一个 KeyValue 枚举中。这是有点乏味的部分,一些代码一遍又一遍地重复,但它确保类型对齐。
enum TableFilterConditionKeyValue: Encodable {
case id_wbs([Int])
case id_object([String])
case id([String])
case period([String])
case type_chart([String])
case tzr_type([String])
case type_of_work([String])
case id_group_object([String])
case report_date([Date])
case operation([String])
enum CodingKeys: String, CodingKey {
case key
case values
}
private var key: String {
switch self {
case .id_wbs(_): "id_wbs"
case .id_object(_): "id_object"
case .id(_): "id"
case .period(_): "period"
case .type_chart(_): "type_chart"
case .tzr_type(_): "tzr_type"
case .type_of_work(_): "type_of_work"
case .id_group_object(_): "id_group_object"
case .report_date(_): "report_date"
case .operation(_): "operation"
}
}
private func encode(_ values: some Encodable, to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(key, forKey: .key)
try container.encode(values, forKey: .values)
}
func encode(to encoder: Encoder) throws {
switch self {
case .id_wbs(let values): try encode(values, to: encoder)
case .id_object(let values): try encode(values, to: encoder)
case .id(let values): try encode(values, to: encoder)
case .period(let values): try encode(values, to: encoder)
case .type_chart(let values): try encode(values, to: encoder)
case .tzr_type(let values): try encode(values, to: encoder)
case .type_of_work(let values): try encode(values, to: encoder)
case .id_group_object(let values): try encode(values, to: encoder)
case .report_date(let values): try encode(values, to: encoder)
case .operation(let values): try encode(values, to: encoder)
}
}
}
这样,您可以按以下方式对 TableFilterConditionItem 进行编码:
struct TableFilterConditionItem: Encodable {
let keyValue: TableFilterConditionKeyValue
let value_derived: TableValueDerived?
init(_ keyValue: TableFilterConditionKeyValue, value_derived: TableValueDerived? = nil) {
self.keyValue = keyValue
self.value_derived = value_derived
}
enum CodingKeys: CodingKey {
case value_derived
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try keyValue.encode(to: encoder)
try container.encodeIfPresent(self.value_derived, forKey: .value_derived)
}
}
这样,您的数据结构就是:
let value = CSITableRequest(filter: TableFilter(conditions: [
TableFilterConditionItem(.id_wbs([1293548])),
TableFilterConditionItem(.id_object([])),
TableFilterConditionItem(.id([""])),
TableFilterConditionItem(.period(["month"])),
TableFilterConditionItem(.type_chart([""])),
TableFilterConditionItem(.tzr_type(["monthly"])),
TableFilterConditionItem(.type_of_work([])),
TableFilterConditionItem(.id_group_object([])),
TableFilterConditionItem(.report_date([]), value_derived:
TableValueDerived(columns: "max_report_date", bo_id: 100006, filter:
TableFilter(conditions: [
TableFilterConditionItem(.id_wbs([1293548])),
TableFilterConditionItem(.operation([])),
])))
]))
评论