Swift JSONDecoder解析URLSession数据时类型不匹配错误求助
解决Swift JSONDecoder解析时的类型不匹配问题
嘿,我来帮你搞定这个卡了你6小时的问题!先看你的错误信息,其实已经把问题说得明明白白了:
typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "itemArr", intValue: nil), CodingKeys(stringValue: "price", intValue: nil)], debugDescription: "Expected to decode String but found a number instead.", underlyingError: nil))
核心问题就是:你在ItemArr模型里把price定义成了String类型,但接口返回的JSON中,price是一个数字类型(可能是整数或浮点数),JSONDecoder没法自动把数字转成字符串,所以就报错了。
下面给你两种靠谱的解决方案,选适合你业务场景的就行:
方案一:直接修改模型属性类型(最简单高效)
如果你的业务逻辑允许把price存为数字类型,直接改模型就完事了。比如接口返回的是整数价格就用Int,带小数就用Double:
class ItemArr : Decodable { let id, title, description: String let price: Double // 或者 Int,根据实际JSON返回调整 let image: String let optionsToShow: Int let gps: Gps let website, phone: String init(id: String, title: String, price: Double, description: String, image: String, optionsToShow: Int, gps: Gps, website: String, phone: String) { self.id = id self.title = title self.price = price self.description = description self.image = image self.optionsToShow = optionsToShow self.gps = gps self.website = website self.phone = phone } }
方案二:自定义解码逻辑(必须保留String类型时)
如果业务上必须把price存成String,那咱们就给ItemArr加个自定义解码方法,既能处理数字转字符串,还能兼容后端万一哪天返回String类型的情况:
class ItemArr : Decodable { let id, title, price, description: String let image: String let optionsToShow: Int let gps: Gps let website, phone: String // 显式声明CodingKeys,确保和JSON字段对应 enum CodingKeys: String, CodingKey { case id, title, price, description, image, optionsToShow, gps, website, phone } // 自定义解码初始化方法 required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 处理price:先试数字转String,不行再试直接读String if let priceNumber = try? container.decode(Double.self, forKey: .price) { self.price = String(priceNumber) } else if let priceString = try? container.decode(String.self, forKey: .price) { self.price = priceString } else { throw DecodingError.dataCorruptedError( forKey: .price, in: container, debugDescription: "Price字段既不是数字也不是字符串" ) } // 其他属性正常解码 self.id = try container.decode(String.self, forKey: .id) self.title = try container.decode(String.self, forKey: .title) self.description = try container.decode(String.self, forKey: .description) self.image = try container.decode(String.self, forKey: .image) self.optionsToShow = try container.decode(Int.self, forKey: .optionsToShow) self.gps = try container.decode(Gps.self, forKey: .gps) self.website = try container.decode(String.self, forKey: .website) self.phone = try container.decode(String.self, forKey: .phone) } // 保留手动初始化的方法(如果需要手动创建实例的话) init(id: String, title: String, price: String, description: String, image: String, optionsToShow: Int, gps: Gps, website: String, phone: String) { self.id = id self.title = title self.price = price self.description = description self.image = image self.optionsToShow = optionsToShow self.gps = gps self.website = website self.phone = phone } }
最后给你两个小Tips:
- 建议把Decodable模型改成
struct而不是class,Swift里值类型的struct更适合做数据模型,而且默认的Decodable实现更省心,不用手动写init方法 - 下次遇到这种问题,先把接口返回的JSON复制出来格式化一下,一眼就能看出字段类型和模型定义的差异,能省不少时间!
内容的提问来源于stack exchange,提问作者Matan
相关产品推荐
相关产品推荐

