Swift中JSONEncoder处理多类型values字段编码问题求助
解决Swift中JSONEncoder多类型values字段编码问题
针对你遇到的values字段需要支持整数、字符串、日期数组的编码问题,这里提供两种实用解决方案:
方案一:带关联值的枚举(推荐,类型安全)
通过定义包含多种类型关联值的枚举,明确对应每个key的values类型,编码逻辑集中在枚举内部,避免类型错误。
步骤1:定义FilterValue枚举
enum FilterValue: Encodable { case ints([Int]) case strings([String]) case dates([Date]) func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .ints(let values): try container.encode(values) case .strings(let values): try container.encode(values) case .dates(let values): // 根据服务器要求的日期格式自定义Formatter let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let dateStrings = values.map(dateFormatter.string(from:)) try container.encode(dateStrings) } } }
步骤2:修改数据模型
将TableFilterConditionItem中的values类型替换为FilterValue:
struct TableFilterConditionItem: Encodable { let key: TableFilterConditionKey let values: FilterValue let value_derived: TableValueDerived? }
使用示例
创建条件项时,根据key传入对应类型的枚举值:
// id_wbs对应整数数组 let idWbsCondition = TableFilterConditionItem( key: .id_wbs, values: .ints([1293548]), value_derived: nil ) // id对应字符串数组(含空字符串) let idCondition = TableFilterConditionItem( key: .id, values: .strings([""]), value_derived: nil ) // report_date对应空数组(用strings或ints的空数组都可,服务器兼容) let reportDateCondition = TableFilterConditionItem( key: .report_date, values: .strings([]), value_derived: TableValueDerived( columns: "max_report_date", bo_id: 100006, filter: TableFilter(conditions: [ TableFilterConditionItem(key: .id_wbs, values: .ints([1293548]), value_derived: nil), TableFilterConditionItem(key: .operation, values: .strings([""]), value_derived: nil) ]) ) )
方案二:自定义编码逻辑(灵活适配现有结构)
如果不想新增枚举,可直接在TableFilterConditionItem中重写encode(to:)方法,根据key的类型动态处理values的编码。
修改后的TableFilterConditionItem
struct TableFilterConditionItem: Encodable { let key: TableFilterConditionKey let values: Any let value_derived: TableValueDerived? func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(key, forKey: .key) // 根据key匹配对应的values类型 switch key { case .id_wbs, .id_object, .id_group_object: guard let intValues = values as? [Int] else { throw EncodingError.invalidValue( values, EncodingError.Context( codingPath: [CodingKeys.values], debugDescription: "key \(key.rawValue) 需传入[Int]类型" ) ) } try container.encode(intValues, forKey: .values) case .id, .period, .type_chart, .tzr_type, .type_of_work, .operation: guard let stringValues = values as? [String] else { throw EncodingError.invalidValue( values, EncodingError.Context( codingPath: [CodingKeys.values], debugDescription: "key \(key.rawValue) 需传入[String]类型" ) ) } try container.encode(stringValues, forKey: .values) case .report_date: // 支持空数组或日期数组(日期自动转字符串) if let dateValues = values as? [Date] { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" try container.encode(dateValues.map(dateFormatter.string(from:)), forKey: .values) } else if let emptyArray = values as? [Any] { try container.encode(emptyArray, forKey: .values) } else { throw EncodingError.invalidValue( values, EncodingError.Context( codingPath: [CodingKeys.values], debugDescription: "key \(key.rawValue) 需传入[Date]或空数组" ) ) } } // 编码可选的value_derived if let valueDerived = value_derived { try container.encode(valueDerived, forKey: .value_derived) } } enum CodingKeys: String, CodingKey { case key, values, value_derived } }
使用示例
创建条件项时需确保values类型与key匹配:
let idWbsCondition = TableFilterConditionItem( key: .id_wbs, values: [1293548] as [Int], value_derived: nil ) let reportDateCondition = TableFilterConditionItem( key: .report_date, values: [] as [Any], value_derived: TableValueDerived( columns: "max_report_date", bo_id: 100006, filter: TableFilter(conditions: [ TableFilterConditionItem(key: .id_wbs, values: [1293548] as [Int], value_derived: nil), TableFilterConditionItem(key: .operation, values: [""] as [String], value_derived: nil) ]) ) )
方案对比
- 方案一类型安全,编译期就能发现类型不匹配问题,适合长期维护的项目。
- 方案二无需额外定义枚举,灵活度高,但需要开发者手动保证
values与key的类型匹配,运行期才会抛出错误。
内容的提问来源于stack exchange,提问作者diclonius9
相关产品推荐
相关产品推荐

