SwiftUI项目无法通过JSON获取数据,该如何解决?
问题描述
学习SwiftUI结合JSON使用时,调用公开API始终报错:无法读取数据,因为格式不正确。
API返回的数据地址为:https://www.abgeordnetenwatch.de/api/v2/politicians
以下是我的代码:
import SwiftUI struct ContentView: View { @State private var politicians: [Politician] = [] @State private var selectedPolitician: Politician? = nil var body: some View { NavigationView { List(politicians, id: \.id) { politician in Button(action: { self.selectedPolitician = politician }) { Text("\(politician.firstName) \(politician.lastName)") } } .navigationTitle("Politicians") .onAppear { self.loadPoliticians() } if let politician = selectedPolitician { PoliticianDetailView(politician: politician) } } } private func loadPoliticians() { let url = URL(string: "https://www.abgeordnetenwatch.de/api/v2/politicians")! URLSession.shared.dataTask(with: url) { data, response, error in if let data = data { do { let decoder = JSONDecoder() let politicians = try decoder.decode([Politician].self, from: data) DispatchQueue.main.async { self.politicians = politicians } } catch { print(error.localizedDescription) } } }.resume() } } struct PoliticianDetailView: View { let politician: Politician var body: some View { VStack { Text("\(politician.firstName) \(politician.lastName)") .font(.title) Text("ID: \(politician.id)") Text("Sex: \(politician.sex)") } .navigationBarTitleDisplayMode(.inline) } } struct Politician: Codable, Identifiable { let id: Int let firstName: String let lastName: String let sex: String enum CodingKeys: String, CodingKey { case id case firstName = "first_name" case lastName = "last_name" case sex } }
问题原因与解决方案
核心问题
你直接尝试将API返回的JSON解析为[Politician].self(Politician数组),但实际API返回的是包含data字段的外层对象,Politician数组嵌套在data字段中。API返回的结构大致如下:
{ "data": [ { "id": 1, "first_name": "...", ... }, ... ], "meta": {...}, "links": {...} }
修改步骤
- 新增外层响应模型:创建结构体匹配API的完整返回结构:
struct PoliticianResponse: Codable { let data: [Politician] }
- 调整解析逻辑:先解析外层响应对象,再提取内部的Politician数组:
private func loadPoliticians() { let url = URL(string: "https://www.abgeordnetenwatch.de/api/v2/politicians")! URLSession.shared.dataTask(with: url) { data, response, error in if let data = data { do { let decoder = JSONDecoder() let response = try decoder.decode(PoliticianResponse.self, from: data) DispatchQueue.main.async { self.politicians = response.data } } catch { // 打印完整错误信息,便于调试定位问题 print("解析错误详情:\(error)") } } }.resume() }
- 字段兼容性优化:部分Politician对象的
sex字段可能为null,需将其改为可选类型避免解析失败:
struct Politician: Codable, Identifiable { let id: Int let firstName: String let lastName: String let sex: String? // 修改为可选类型 enum CodingKeys: String, CodingKey { case id case firstName = "first_name" case lastName = "last_name" case sex } }
同时在PoliticianDetailView中处理可选值:
Text("Sex: \(politician.sex ?? "未提供")")
内容的提问来源于stack exchange,提问作者Al Ko
相关产品推荐
相关产品推荐

