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。建议:
- 在Storyboard中给你的TableViewCell设置一个复用标识符(比如
"BonusCell") - 修改
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
相关产品推荐
相关产品推荐

