Swift使用List加载联系人API的JSON数据报Key path类型转换错误如何解决
问题修复方案
错误原因
你遇到的类型不匹配报错由三个核心问题导致:
- List初始化参数传值错误:你调用的List构造方法要求第一个参数是可遍历的数组,但你传入的
fetch.contacts是Response类型的单对象,不是联系人数组,泛型参数无法匹配 - 重复定义类型:你在
Response结构体中已经定义了Contacts子结构体,又在ContentView中重复定义了一次同名结构体,两套类型不兼容 - 数据访问逻辑错误:你在List行视图中尝试用
contact.data.first_name取值,就算遍历逻辑正确,单条联系人数据也不需要额外访问data属性
修复后的完整代码
import SwiftUI struct Response: Codable { // 添加Identifiable协议遵循,直接适配List遍历要求 struct Contacts: Codable, Identifiable { public let id: Int public let first_name: String public let last_name: String public let updated_date: String } struct Pagination_Data: Codable { public let skip: Int public let limit: Int public let total: Int } // 这个自定义的response属性不需要参与解码,保留即可 public let response = UUID().uuidString public let data: [Contacts] public let pagination: Pagination_Data enum CodingKeys : String, CodingKey { case data = "data" case pagination = "pagination" } } struct ContentView: View { @ObservedObject var fetch = FetchContacts() // 移除重复定义的Contacts结构体,统一用Response.Contacts var body: some View { VStack { // 加加载状态判断,优化体验 if let contacts = fetch.contacts { // 直接遍历Response里的data数组,因为Contacts遵循Identifiable不需要额外指定id List(contacts.data) { contact in VStack(alignment: .leading) { Text(contact.first_name) Text(contact.last_name) .font(.subheadline) .foregroundColor(.secondary) } } } else { ProgressView("联系人加载中...") } } } } class FetchContacts: ObservableObject { // 改成可选类型,避免没有初始值的编译错误,请求成功后再赋值 @Published var contacts: Response? init() { let url = URL(string: "替换为你的实际接口地址")! URLSession.shared.dataTask(with: url) {(data, response, error) in do { if let contactData = data { let decodedData = try JSONDecoder().decode(Response.self, from: contactData) DispatchQueue.main.async { self.contacts = decodedData let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let data = try! encoder.encode(decodedData) print(String(data: data, encoding: .utf8)!) } } else { print("无返回数据") } } catch { print("解码错误: \(error)") } }.resume() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
核心修改点
- 给
Response.Contacts添加Identifiable协议遵循,利用自带的id属性直接适配List的遍历要求 - 将
FetchContacts中的contacts属性改为可选类型,消除无初始值的编译错误,网络请求成功后再赋值 - 移除
ContentView中重复定义的Contacts结构体,全局统一使用Response.Contacts类型 - 修正List的数据源为Response下的
data数组,符合List对可遍历集合的参数要求 - 新增加载状态判断,优化无数据时的展示体验
- 优化错误打印逻辑,方便后续排查接口问题
内容的提问来源于stack exchange,提问作者Mathisha Karunaratne
相关产品推荐
相关产品推荐

