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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:25:41