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

TableView未加载数据但JSON文件已解析的问题排查

解决TableView无法加载JSON数据的问题

我一眼就看到了问题的核心——你解码完JSON后,没有把获取到的bonuses数据赋值给全局的bonuses数组!这就是为什么numberOfRowsInSection打印的bonuses.count始终为0,TableView一直空白的原因。

1. 修复核心数据赋值问题

你的downloadJSON方法里,已经成功解码出了posts对象,但没有把posts.bonuses赋值给全局的bonuses变量。修改后的代码应该这样:

func downloadJSON(completed: @escaping () -> ()) {
    guard let url = URL(string: "http://tourofhonor.com/BonusData.json") else {
        print("Invalid URL")
        return
    }
    
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let error = error {
            print("Network error: \(error)")
            return
        }
        
        guard let data = data else {
            print("No data received")
            return
        }
        
        do {
            let posts = try JSONDecoder().decode(JsonFile.self, from: data)
            // 关键:将解码后的数据赋值给全局数组,并在主队列更新UI
            DispatchQueue.main.async {
                self.bonuses = posts.bonuses
                completed()
            }
            print(posts.bonuses.map {$0.bonusCode})
        } catch {
            print("JSON解码失败:\(error)") // 打印具体错误,方便调试
        }
    }.resume()
}

这里还做了几个实用优化:

  • 用guard let安全处理URL和数据,避免强制解包导致崩溃
  • 分步骤处理网络错误和空数据的情况
  • 将数据赋值和UI更新(completed()里的reloadData)都放在主队列,确保线程安全

2. 解释打印顺序的问题

你看到的打印顺序(先三次0,然后bonusCode,再一次0)是因为:

  • URLSession.dataTask是异步执行的,viewDidLoad调用downloadJSON后,会立刻执行TableView的数据源方法,这时候bonuses还是空数组,所以打印0
  • 等异步网络请求完成并解码后,你之前的代码没有赋值bonuses,所以调用completed()执行reloadData时,bonuses依然是空的,再次打印0
  • 而posts.bonuses.map的打印是在异步任务里,所以会在中间出现

3. 解决行高不一致的问题

部分行显示不同垂直高度,大概率是因为你没有正确复用TableViewCell。建议:

  1. 在Storyboard中给你的TableViewCell设置一个复用标识符(比如"BonusCell")
  2. 修改cellForRowAt方法,使用复用机制:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "BonusCell", for: indexPath)
    cell.textLabel?.text = bonuses[indexPath.row].name.capitalized
    return cell
}

如果需要自适应行高,可以在viewDidLoad里添加:

tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 44 // 设置一个合适的预估高度

4. 可选值安全优化

在prepare(for:sender:)里,不要强制解包tableView.indexPathForSelectedRow,改用可选绑定避免崩溃:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? HeroViewController,
       let indexPath = tableView.indexPathForSelectedRow {
        destination.bonus = bonuses[indexPath.row]
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:41:50