SwiftUI中API调用异常:JSON解码与bedwars_stats获取问题
问题排查与修复方案
核心问题分析
从你的代码和JSON结构来看,主要有以下几个导致解码失败的原因:
- 结构体命名冲突:
Result是Swift标准库中的内置类型,自定义同名结构体会引发编译歧义 - 字符串插值语法错误:Text组件里的
(item.achievements.bedwars_stats)缺少反斜杠,正确写法应为\(item.achievements.bedwars_stats) - 解码异常被忽略:使用
try?会吞掉解码过程中的错误信息,无法定位具体问题 - URL变量名重复:
URL(string: url)里的url变量名重复,应替换为具体的URL字符串常量 - 潜在类型不匹配:如果JSON中的
bedwars_stats是带引号的字符串类型,而你用Int接收会直接解码失败 - ForEach标识风险:用
bedwars_stats作为唯一id可能出现重复,建议给结构体实现Identifiable协议
修正后的完整代码
import SwiftUI // 重命名结构体避免和标准库Result冲突 struct PlayerResponse: Codable { let results: [PlayerResult] } struct PlayerResult: Codable, Identifiable { // 实现Identifiable协议生成唯一标识,也可改用JSON中自带的唯一字段 var id: UUID { UUID() } let achievements: PlayerAchievements } struct PlayerAchievements: Codable { // 若JSON中bedwars_stats是字符串类型,将此处改为String即可 let bedwars_stats: Int } struct ContentView: View { @State private var results: [PlayerResult] = [] var body: some View { VStack { ForEach(results) { item in // 修正字符串插值语法 Text("\(item.achievements.bedwars_stats)") } } .task { await loadData() } } func loadData() async { // 替换为你的实际API地址 guard let url = URL(string: "你的目标API地址") else { print("无效URL") return } do { let (data, _) = try await URLSession.shared.data(from: url) // 用try代替try?,打印具体错误信息 let decodedResponse = try JSONDecoder().decode(PlayerResponse.self, from: data) results = decodedResponse.results } catch { // 打印解码错误,快速定位问题 print("解码失败详情:\(error)") } } }
额外调试技巧
- 打印原始JSON数据:在解码前添加
print(String(data: data, encoding: .utf8)),确认拿到的JSON结构是否和预期一致 - 检查字段匹配:JSON的键名必须和结构体属性完全一致(包括下划线、大小写),若JSON用驼峰命名,可设置
JSONDecoder的keyDecodingStrategy = .convertFromSnakeCase - 调整结构体层级:如果你的JSON根节点不是
results数组,而是直接包含achievements的单个对象,需修改PlayerResponse结构,比如:
struct PlayerResponse: Codable { let achievements: PlayerAchievements }
内容的提问来源于stack exchange,提问作者Tom Miller
相关产品推荐
相关产品推荐

