Swift如何正确读取本地JSON文件并赋值给Codable结构体?
本地JSON与Codable结构体映射实现方案
问题核心原因
- 现有代码中使用的
JSONSerialization仅能将JSON数据转换为Foundation基础类型(字典/数组/字符串/数字等),无法自动完成与自定义结构体的映射,需要使用JSONDecoder完成Codable类型的解码 - 定义的结构体属性名与JSON实际的key不匹配,必须手动声明
CodingKeys建立映射关系,否则解码器无法找到对应字段会直接抛出错误 - 外层
Countries结构体仅在JSON根节点为{"results": [国家数组]}格式时才需要使用,从现有代码逻辑判断,当前JSON根节点是数组类型,不需要套这层结构。
第一步:修正结构体定义,添加映射关系
struct Country: Codable { var aNumber: Int var cName: String var population: Int var landArea: Int var density: Int var facts: String // 枚举case对应结构体属性名,rawValue对应JSON里的实际key enum CodingKeys: String, CodingKey { case aNumber = "#" case cName = "Country" case population = "Population\n(2020)" case landArea = "Land Area\n(Km²)" case density = "Density\n(P/Km²)" case facts = "FACTS" } } // 仅当JSON根结构为带results字段的字典时保留,根节点为数组可直接删除 struct Countries: Codable { var results: [Country] }
第二步:替换读取逻辑,使用JSONDecoder解码
直接丢弃JSONSerialization相关逻辑,用解码器直接把Data转成目标类型:
private func readJson() { do { guard let fileURL = Bundle.main.url(forResource: "csvjson", withExtension: "json") else { print("本地JSON文件不存在,请检查文件是否加入项目Target") return } let jsonData = try Data(contentsOf: fileURL) let decoder = JSONDecoder() // 根据JSON实际根结构二选一: // 1. 根节点为数组(现有代码判断走了数组分支,用这行即可) let countryList = try decoder.decode([Country].self, from: jsonData) print("解析完成,共加载\(countryList.count)条国家数据") // 2. 根节点为带results的字典时,注释上面两行,用下面的代码 // let result = try decoder.decode(Countries.self, from: jsonData) // let countryList = result.results } catch { // 直接打印error对象,会明确指出缺失字段、类型不匹配等具体错误原因 print("JSON解析失败:\(error)") } }
排查注意事项
- 不要用
error.localizedDescription获取解码错误,本地化描述只会显示笼统的“数据损坏”信息,直接打印error对象可以拿到精准到字段的错误提示,排查效率高很多 - 确保本地JSON文件格式合法,提供的JSON示例缺少结尾的闭合
},实际文件要补全格式,否则会解码失败 - 选中本地JSON文件,在右侧File Inspector的Target Membership里勾选当前项目target,否则Bundle无法找到文件
- 如果后续JSON的key有变更,只需要修改CodingKeys里对应的rawValue即可,不需要修改业务层使用的结构体属性名
内容的提问来源于stack exchange,提问作者RyanW
相关产品推荐
相关产品推荐

