Swift 4 JSON Codable遇"None"类型赋值报错求解决方案
哈哈,这个问题我前段时间刚踩过坑!后端用字符串"None"来表示空值,但我们的Codable模型属性是Int/Double这类非String类型,直接解析肯定会报错,因为类型完全不匹配。给你几个实用的解决思路,你可以根据自己的场景选:
思路1:自定义包装类型(最推荐,扩展性强)
针对需要处理"None"的类型,写一个通用的包装器来兼容字符串和目标类型的解析:
struct OptionalWrapper<T: Codable>: Codable { let value: T? init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() do { // 先尝试解析成目标类型 value = try container.decode(T.self) } catch { // 解析失败就尝试读字符串 let stringValue = try container.decode(String.self) if stringValue == "None" { value = nil } else { // 非"None"的字符串可以选择抛出错误,或者尝试转成目标类型 throw DecodingError.dataCorruptedError(in: container, debugDescription: "Expected \(T.self) or 'None' string") } } } }
然后在模型里直接用这个包装器代替可选类型:
struct User: Codable { let id: OptionalWrapper<Int> let balance: OptionalWrapper<Double> }
如果只需要针对某一种类型处理,也可以写非泛型的版本,比如OptionalInt、OptionalDouble,逻辑是一样的。
思路2:全局替换"None"为null(简单粗暴,适合统一场景)
如果后端所有的空值都是用"None"表示,没有其他地方需要保留这个字符串,那可以先把JSON里的"None"替换成null再解析:
// 假设你拿到的是JSON Data guard let jsonString = String(data: jsonData, encoding: .utf8) else { // 处理数据转换失败 return } // 替换所有"None"字符串为null let modifiedJsonString = jsonString.replacingOccurrences(of: "\"None\"", with: "null") guard let modifiedData = modifiedJsonString.data(using: .utf8) else { return } let decoder = JSONDecoder() do { let model = try decoder.decode(YourTargetModel.self, from: modifiedData) // 处理解析后的模型 } catch { print("解析错误:\(error)") }
注意:这个方法要谨慎用,如果你的JSON里有某个字段本来就需要存储"None"字符串,会被误替换成null。
思路3:模型内手动处理(适合个别字段)
如果只有少数几个字段存在"None"的情况,直接在模型的自定义解码方法里处理更灵活:
struct Product: Codable { let price: Double? let stockCount: Int? enum CodingKeys: String, CodingKey { case price, stockCount } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 处理price字段 do { price = try container.decode(Double.self, forKey: .price) } catch { let priceStr = try container.decode(String.self, forKey: .price) price = priceStr == "None" ? nil : Double(priceStr) } // 处理stockCount字段 do { stockCount = try container.decode(Int.self, forKey: .stockCount) } catch { let stockStr = try container.decode(String.self, forKey: .stockCount) stockCount = stockStr == "None" ? nil : Int(stockStr) } } }
这种方式不用额外写包装类型,针对性处理个别字段,代码也更直观。
内容的提问来源于stack exchange,提问作者user3088688
相关产品推荐
相关产品推荐

