You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 20:04:54