Swift中解析含动态键的JSON报错,如何编写正确的Codable模型?
处理含动态键的JSON数据的Codable模型实现
先模拟一个符合你描述的JSON结构(包含动态球队ID、动态球员ID,以及球员的姓名、击球/投球数据):
示例JSON:
{ "teams": { "4": { "players": { "3632": { "name": "John Doe", "batting_stats": { "average": 0.320, "home_runs": 12 }, "pitching_stats": { "era": 3.25, "strikeouts": 85 } }, "3752": { "name": "Jane Smith", "batting_stats": { "average": 0.285, "home_runs": 8 }, "pitching_stats": { "era": 2.90, "strikeouts": 92 } } } }, "5": { "players": { "4101": { "name": "Mike Johnson", "batting_stats": { "average": 0.305, "home_runs": 15 }, "pitching_stats": { "era": 3.50, "strikeouts": 78 } } } } } }
核心思路
动态键没法直接映射到固定属性名,所以用[String: 对应模型]的字典类型承接这些动态键,再配合基础数据模型就能正常解码。
1. 定义基础数据模型
先把球员的击球、投球数据和球员本身的模型写好:
// 击球数据模型 struct BattingStats: Codable { let average: Double let homeRuns: Int // 处理JSON里的蛇形键转驼峰命名 enum CodingKeys: String, CodingKey { case average case homeRuns = "home_runs" } } // 投球数据模型 struct PitchingStats: Codable { let era: Double let strikeouts: Int } // 球员模型 struct Player: Codable { let name: String let battingStats: BattingStats let pitchingStats: PitchingStats enum CodingKeys: String, CodingKey { case name case battingStats = "batting_stats" case pitchingStats = "pitching_stats" } }
2. 定义球队与顶层数据模型
球队里的球员是动态ID,用[String: Player]存储;顶层的球队也是动态ID,用[String: Team]存储:
// 球队模型 struct Team: Codable { let players: [String: Player] } // 顶层数据模型 struct BaseballData: Codable { let teams: [String: Team] }
3. 解码JSON数据
直接用JSONDecoder就能正常解码,还能开启自动蛇形键转驼峰减少手动写CodingKeys的工作量:
func decodeBaseballData(from jsonData: Data) -> BaseballData? { do { let decoder = JSONDecoder() // 自动把JSON里的蛇形键(比如home_runs)转成Swift的驼峰命名(homeRuns) decoder.keyDecodingStrategy = .convertFromSnakeCase let data = try decoder.decode(BaseballData.self, from: jsonData) return data } catch { print("解码出错:\(error)") return nil } }
4. 提取并展示球员数据
如果需要把所有球员的信息提取出来展示,直接遍历字典即可:
// 假设你已经拿到了JSON的Data对象yourJsonData if let baseballData = decodeBaseballData(from: yourJsonData) { var allPlayers: [Player] = [] // 遍历所有球队 for (_, team) in baseballData.teams { // 遍历球队里的所有球员 for (_, player) in team.players { allPlayers.append(player) } } // 打印展示球员信息 for player in allPlayers { print("球员姓名:\(player.name)") print("击球数据:命中率\(player.battingStats.average),本垒打\(player.battingStats.homeRuns)") print("投球数据:防御率\(player.pitchingStats.era),三振数\(player.pitchingStats.strikeouts)\n") } }
内容的提问来源于stack exchange,提问作者Manjunath C.Kadani
相关产品推荐
相关产品推荐

