Swift中跨控制器调用reloadData()后UITableView显示错乱的问题排查与修复
解决UITableView刷新后单元格显示错乱的问题
这个问题太典型了——UITableViewCell的复用机制没处理好!你遇到的显示错乱,本质是因为cell被复用时,之前设置的样式属性没有被重置,导致旧状态残留到了新的单元格上。
问题根源
在你的cellForRowAt方法里,只有前两个条件分支(已完成、当前工作项)设置了textColor、accessoryType和isUserInteractionEnabled,但当cell被复用到第三个分支(未解锁项)时,这些属性会保留上一次的设置值。比如原本显示黄色文字的cell被复用到未解锁行,文字颜色就会错误地保持黄色,最终导致错乱。
修复方案
每次复用cell时,必须重置所有可能影响显示的属性——要么在赋值前统一恢复默认状态,要么在每个条件分支里明确设置所有相关属性,不能遗漏任何分支。
修改后的代码
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell", for: indexPath) as! CellController // 先重置所有可能复用残留的属性(根据你的默认样式调整) cell.cost.textColor = UIColor.label cell.accessoryType = .disclosureIndicator cell.isUserInteractionEnabled = true // 安全解包避免崩溃,替代强制解包 guard let levels = self.gameView.data?.levels, let currentGame = self.gameView.game else { return cell } let currentItem = levels[indexPath.row] cell.model.text = currentItem.name if currentItem.id < currentGame.level.id { cell.cost.text = "Complete" cell.cost.textColor = UIColor.systemGreen cell.accessoryType = .none cell.isUserInteractionEnabled = false } else if currentItem.id == currentGame.level.id { cell.cost.text = "Employee" cell.cost.textColor = UIColor.systemYellow cell.accessoryType = .none cell.isUserInteractionEnabled = false } else { cell.cost.text = "\(currentItem.XP) XP" // 这里默认样式已经在开头重置过,无需重复设置 } return cell }
额外优化建议
- 避免使用
!强制解包self.gameView.data和self.gameView.game,用guard let做安全校验,防止空值崩溃; - 可以考虑把cell的样式逻辑封装到CellController内部,比如给CellController加一个
configure(with item: Level, currentLevel: Level)方法,让代码更清晰,也更容易维护。
内容的提问来源于stack exchange,提问作者Javi Albors
相关产品推荐
相关产品推荐

