SwiftUI中内部API结构体解析失败问题求助
问题描述
我是SwiftUI新手,此前调用外部API的代码运行正常。添加结构体Partei后,出现三类错误:
- 58:28 Generic parameter 'T' could not be inferred -> 调用
Foundation.JSONDecoder的decode(_:from:)函数时触发 - 58:43 Cannot convert value of type 'module' to expected argument type 'T.Type'
- 108:88 Missing argument for parameter 'partei' in call -> 此处声明了
init(politician:partei:)
需求:在PoliticianDetailView中展示Partei结构体的文本信息,计划添加代码:
List(viewModel.parteien, id: \.parteiID) { partei in Text("Partei: \(partei.namePartei)") }
错误修复与完整代码
错误1、2的修复
ParteiDataService中调用decode(Parteien.self, from: data)时,Parteien结构体未定义,导致JSON解析失败。需要添加和Politicians结构一致的解析结构体:
struct Parteien: Decodable { let data: [Partei] }
错误3的修复
PoliticianDetailView声明了let partei: Partei参数,但Politician结构体已经包含partei属性,无需单独传递该参数。直接移除PoliticianDetailView中的let partei: Partei即可,跳转时只传politician参数。
完整修复代码
import SwiftUI struct Partei: Decodable { let parteiID: Int let namePartei: String private enum CodingKeys: String, CodingKey { case parteiID = "id" case namePartei = "label" } } struct Politician: Decodable { let id: Int let firstName: String let lastName: String let birthYear: Int? let beruf: String? let geschlecht: String? let partei: Partei enum CodingKeys: String, CodingKey { case id case firstName = "first_name" case lastName = "last_name" case birthYear = "year_of_birth" case beruf = "occupation" case geschlecht = "sex" case partei } } struct Politicians: Decodable { let data: [Politician] } // 新增政党列表解析结构体 struct Parteien: Decodable { let data: [Partei] } actor PoliticianDataService { func fetchPoliticians() async throws -> [Politician] { guard let url = URL(string: "https://www.abgeordnetenwatch.de/api/v2/politicians") else { return [] } let (data, _) = try await URLSession.shared.data(from: url) let decoder = JSONDecoder() let politicians = try decoder.decode(Politicians.self, from: data) return politicians.data } } actor ParteiDataService { func fetchParteien() async throws -> [Partei] { guard let url = URL(string: "https://www.abgeordnetenwatch.de/api/v2/parties") else { return [] } let (data, _) = try await URLSession.shared.data(from: url) let decoder = JSONDecoder() let parteien = try decoder.decode(Parteien.self, from: data) return parteien.data } } @MainActor class PoliticianListViewModel: ObservableObject { @Published var politicians = [Politician]() private var dataService = PoliticianDataService() init() { // 可在此添加额外初始化逻辑 } func fetchPoliticians() { Task { do { let fetchedPoliticians = try await dataService.fetchPoliticians() politicians = fetchedPoliticians } catch { print(error) } } } } class PoliticianDetailViewModel: ObservableObject { @Published var parteien = [Partei]() private var dataService = ParteiDataService() func fetchParteien() { Task { do { let fetchedParteien = try await dataService.fetchParteien() parteien = fetchedParteien } catch { print(error) } } } } struct ContentView: View { @StateObject var viewModel = PoliticianListViewModel() var body: some View { NavigationView { List(viewModel.politicians, id: \.id) { politician in NavigationLink(destination: PoliticianDetailView(politician: politician)) { Text("\(politician.firstName) \(politician.lastName)") } } .navigationTitle("Politiker in Deutschland") } .onAppear { viewModel.fetchPoliticians() } } } struct PoliticianDetailView: View { let politician: Politician @StateObject private var viewModel = PoliticianDetailViewModel() var body: some View { VStack { Text("Name: \(politician.firstName) \(politician.lastName)") Text("Geburtsjahr \(politician.birthYear ?? 0)") Text("Alter: \(calculateAge(birthYear: politician.birthYear ?? 0)) Jahre") Text("Beschäftigt als \(politician.beruf ?? "Unbekannt")") Text("Geschlecht: \(politician.geschlecht ?? "Unbekannt")") // 可选:直接展示当前政客所属政党 Text("Partei: \(politician.partei.namePartei)") // 展示所有政党列表(按需求保留) List(viewModel.parteien, id: \.parteiID) { partei in Text("Partei: \(partei.namePartei)") } .onAppear { viewModel.fetchParteien() } } .navigationTitle("\(politician.firstName) \(politician.lastName)") } func calculateAge(birthYear: Int) -> Int { let currentYear = Calendar.current.component(.year, from: Date()) return currentYear - birthYear } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
额外说明
- 如果仅需展示当前政客的政党信息,无需调用政党列表API,直接使用
politician.partei.namePartei即可,可简化代码移除ParteiDataService和PoliticianDetailViewModel相关逻辑。 - 如果需要展示全量政党列表,保留当前API调用逻辑即可,修复后的代码可正常运行。
内容的提问来源于stack exchange,提问作者Alko Nama
相关产品推荐
相关产品推荐

