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
相关产品推荐
相关产品推荐

