You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift使用List加载联系人API的JSON数据报Key path类型转换错误如何解决

问题修复方案

错误原因

你遇到的类型不匹配报错由三个核心问题导致:

  1. List初始化参数传值错误:你调用的List构造方法要求第一个参数是可遍历的数组,但你传入的fetch.contacts是Response类型的单对象,不是联系人数组,泛型参数无法匹配
  2. 重复定义类型:你在Response结构体中已经定义了Contacts子结构体,又在ContentView中重复定义了一次同名结构体,两套类型不兼容
  3. 数据访问逻辑错误:你在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 07:24:03