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

Swift中API编码报错「数据格式不正确」的原因及修复

问题原因分析
  • 核心矛盾是AnyCodable对null值的编码逻辑缺陷:当API返回equationValue: null时,若你的BaseModel用AnyCodable承载该字段,null会被解析为NSNull(而非Swift原生的nil),而默认的AnyCodable实现通常未处理NSNull的编码逻辑,导致JSONEncoder执行时抛出格式错误。
  • 另外可能的诱因:BaseModel中equationValue的类型未定义为原生可选String?,而是被AnyCodable包裹,即便PlotModel是可选类型,编码BaseModel时,未转换的NSNull值依然会触发编码失败。
修复方案

方案1:移除不必要的AnyCodable,严格匹配API结构

直接将BaseModel的字段类型与API响应一一对应,避免用AnyCodable模糊兼容:

// 定义与API响应严格对应的BaseModel结构
struct BaseModel: Codable {
    let resultData: [ResultItem]
    // 其他字段...
}

struct ResultItem: Codable {
    let equationValue: String? // 明确为可选String,自动兼容API的null/非空字符串
    // 其他字段...
}

此时API返回的null会被直接解析为Swift的nil,JSONEncoder可正常处理可选类型的nil(默认会忽略该字段,若需保留null可配置encoder.outputFormatting)。

方案2:自定义AnyCodable,兼容NSNull编码

若因API结构多变必须使用AnyCodable,需修改其编码逻辑,处理NSNull场景:

struct AnyCodable: Codable {
    let value: Any

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if container.decodeNil() {
            value = NSNull()
        } else if let string = try? container.decode(String.self) {
            value = string
        } else if let number = try? container.decode(Int.self) {
            value = number
        }
        // 按需扩展其他支持的类型(如Bool、Double等)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch value {
        case let string as String:
            try container.encode(string)
        case let number as Int:
            try container.encode(number)
        case is NSNull:
            try container.encodeNil() // 关键:将NSNull编码为JSON的null
        default:
            throw EncodingError.invalidValue(value, EncodingError.Context(
                codingPath: encoder.codingPath,
                debugDescription: "不支持的编码类型"
            ))
        }
    }
}

方案3:转换流程中清理无效类型

在convertToModel方法中,确保将BaseModel中的equationValue转换为PlotModel可识别的可选String,过滤掉NSNull:

func convertToModel(from baseModel: BaseModel) -> [PlotModel] {
    return baseModel.resultData.map { item in
        // 处理AnyCodable包裹的字段,转换为可选String
        let equationValue: String? = {
            guard let anyVal = item.equationValue as? AnyCodable else {
                return item.equationValue as? String
            }
            return anyVal.value as? String
        }()
        return PlotModel(equationValue: equationValue)
    }
}

内容的提问来源于stack exchange,提问作者Fahim Parkar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:09:58