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

请求协助排查iOS Swift中WebAPI数据获取失败问题

问题解决步骤

1. 核心问题:JSON解析失败(缺失必填字段)

错误日志明确指出找不到carbohydrates字段,说明你的FruitData模型中将该属性声明为必填,但API返回的部分水果数据里没有这个字段。

修正FruitData模型

将所有可能缺失的字段改为可选类型(添加?),包括嵌套的Nutritions结构体属性:

struct FruitData: Codable {
    let name: String
    let id: Int?
    let family: String?
    let order: String?
    let genus: String?
    let nutritions: Nutritions?
    
    struct Nutritions: Codable {
        let carbohydrates: Double?
        let protein: Double?
        let fat: Double?
        let calories: Int?
        let sugar: Double?
    }
}

这样即使部分字段缺失,JSONDecoder也能正常解析,不会抛出keyNotFound错误。

2. 修复代码中的低级错误

  • 表格刷新对象错误:你在fetchApi的完成闭包里调用了self.tableView.reloadData(),但表格的IBOutlet是fruitTable,应改为:
    fetchApi{
        self.fruitTable.reloadData()
    }
    
  • 安全解包URL与数据:原代码的强制解包容易崩溃,改为安全绑定逻辑:
    func fetchApi(completed: @escaping () -> ()) {
        guard let url = URL(string: "https://fruityvice.com/api/fruit/all") else {
            print("无效的URL")
            return
        }
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                print("网络请求失败:\(error)")
                return
            }
            guard let data = data else {
                print("未获取到数据")
                return
            }
            do {
                self.fruits = try JSONDecoder().decode([FruitData].self, from: data)
                DispatchQueue.main.async {
                    completed()
                }
            } catch {
                print("JSON解析失败:\(error)")
            }
        }.resume()
    }
    
  • 提前设置代理:把fruitTable.delegate = self和fruitTable.dataSource = self放在fetchApi调用之前,避免数据加载完成时代理未初始化。

3. 补充UITableView数据源方法

当前代码仅遵循了协议但未实现核心数据源方法,需添加:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return fruits.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "FruitCell", for: indexPath)
    cell.textLabel?.text = fruits[indexPath.row].name
    return cell
}

注意将"FruitCell"替换为你在Storyboard中设置的单元格标识符。


内容的提问来源于stack exchange,提问作者Toya Tanaj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 13:10:49