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

Xcode项目JSON解码失败:SwiftUI Codable数据模型适配排查

JSON解码失败问题定位与修复

核心问题点

  • 数据模型字段类型和JSON实际值类型不匹配:JSON中lat、lng字段存储的是浮点数,City结构体却将两个字段定义为String类型,类型不匹配直接触发解码失败。
  • id字段无对应数据源:City遵循Identifiable协议定义了UUID类型的id属性,但提供的JSON数据中没有id对应的键值,默认合成的Codable实现会尝试从JSON中解析id字段,找不到对应键就会抛出错误。
  • 解码辅助函数吞掉了具体错误信息:现有Bundle扩展中使用try?屏蔽了解码过程的具体错误,只会抛出笼统的“解码失败”提示,无法定位具体出错字段。

分步修复方案

1. 修正City数据模型

将经纬度字段类型改为和JSON匹配的Double,同时给id设置默认值并排除在解码逻辑外,不需要修改JSON内容:

import SwiftUI

struct City: Codable, Identifiable {
    var id = UUID()
    var name: String
    var image: String
    var lat: Double
    var lng: Double
    var description: String
    
    // 指定参与解码的字段,排除id,解码时自动用默认生成的UUID赋值
    enum CodingKeys: String, CodingKey {
        case name, image, lat, lng, description
    }
}

经纬度本身是数值类型,用Double存储也方便后续调用地图框架做坐标计算,不需要额外做类型转换。

2. 优化解码辅助函数,输出具体错误

修改Bundle扩展的解码逻辑,不要用try?吞掉错误,遇到解码失败时打印具体错误信息,后续再遇到同类问题可以直接看到出错字段和原因:

import UIKit

extension Bundle {
    func decode<T: Decodable>(_ type: T.Type, from file: String) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }

        guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")
        }

        let decoder = JSONDecoder()
        do {
            let loaded = try decoder.decode(T.self, from: data)
            return loaded
        } catch {
            fatalError("Failed to decode \(file) from bundle: \(error)")
        }
    }
}

修改后如果再出现解码错误,控制台会直接输出类似“期望String类型但发现Number类型”、“找不到id对应的键”这类明确提示,不需要再盲查问题。

3. 配置检查

  • 选中项目中的cities.json文件,在右侧File Inspector面板的Target Membership分组下,确认当前app target对应的勾选框是选中状态,否则会报找不到文件的错误。
  • 确认ItemRow、ItemDetail视图的入参类型为City,和ForEach遍历的元素类型保持一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 02:24:14