iOS TableView切换待办状态后数据不显示问题求助
问题描述
应用启动时可正常显示ToDo数组,但将待办项切换至“In Progress”或“Done”状态后,再次返回“To Do”状态时,toDoGoals数组无法在TableView中显示,仅能看到最后点击的分区内容。
问题复现截图
- 应用启动并选中ToDo状态

- 选中InProgress状态

- 选中Done状态

- 再次选中ToDo状态

现有代码
HomeViewModel
import Foundation protocol HomeViewModelInterface { var view: HomeScreenInterface? { get set } func viewDidLoad() func viewToDoGoals() func viewInProgressGoals() func viewDoneGoals() } final class HomeViewModel { weak var view: HomeScreenInterface? var progressSections: [String] = ["To Do","In Progress","Done"] lazy var toDoGoals: [ToDoModel] = [ ToDoModel(title: "ToDo 1"), ToDoModel(title: "Todo 2"), ToDoModel(title: "ToDo 3") ] lazy var inProgressGoals: [ToDoModel] = [ ToDoModel(title: "Progress 1"), ToDoModel(title: "Progress 2"), ToDoModel(title: "Progress 3") ] lazy var done: [ToDoModel] = [ ToDoModel(title: "Done 1"), ToDoModel(title: "Done 2"), ToDoModel(title: "Done 3") ] } extension HomeViewModel: HomeViewModelInterface { func viewDidLoad() { view?.configureVC() view?.configureCollectionView() view?.configureTableView() } func viewToDoGoals() { self.view?.updateTableView(with: self.toDoGoals) print("View todo") } func viewInProgressGoals() { self.view?.updateTableView(with: self.inProgressGoals) print("View progress") } func viewDoneGoals() { self.view?.updateTableView(with: self.done) print("View Done.") } }
HomeScreen
protocol HomeScreenInterface: AnyObject { func configureVC() func configureCollectionView() func configureTableView() func updateTableView(with goals: [ToDoModel]) } final class HomeScreen: UIViewController { override func viewDidLoad() { super.viewDidLoad() viewModel.view = self viewModel.viewDidLoad() } } extension HomeScreen: HomeScreenInterface { func configureVC() { title = "To Do ✅" view.backgroundColor = .systemBackground } // Update TableView Array func updateTableView(with goals: [ToDoModel]) { viewModel.toDoGoals = goals DispatchQueue.main.async { self.goalsTableView.reloadData() } } }
TableView 代理与数据源方法
extension HomeScreen: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return viewModel.toDoGoals.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: GoalsCells.reuseIdentifier, for: indexPath) as? GoalsCells else { return UITableViewCell() } cell.delegate = self let goals = viewModel.toDoGoals[indexPath.row] cell.setGoalCell(goal: goals.title, checked: goals.isComplete) return cell } }
CollectionView 代理与数据源方法
extension HomeScreen: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ProgressCells.reuseIdentifier, for: indexPath) as? ProgressCells else { return UICollectionViewCell() } cell.setCell(progress: viewModel.progressSections[indexPath.item]) return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { switch indexPath.item { case 0: // To Do self.viewModel.viewToDoGoals() case 1: // In Progress self.viewModel.viewInProgressGoals() case 2: // Done self.viewModel.viewDoneGoals() default: break } } }
ToDoModel
import Foundation struct ToDoModel { let title: String let isComplete: Bool init(title: String, isComplete: Bool = false) { self.title = title self.isComplete = isComplete } func completeToggled() -> ToDoModel { return ToDoModel(title: title, isComplete: !isComplete) } }
问题根源
核心问题出在HomeScreen的updateTableView(with:)方法中:每次切换状态时,你把传入的目标数组直接赋值给了viewModel.toDoGoals,这会覆盖掉toDoGoals的原始数据。比如切换到“In Progress”后,toDoGoals就变成了inProgressGoals的内容,当你再次切回“To Do”时,viewModel.viewToDoGoals()传递的已经是被覆盖后的数组,而非初始的ToDo数据。
修复方案
通过在ViewModel中维护一个当前显示数组,避免修改原始数据数组,就能解决这个问题:
1. 修改HomeViewModel
添加currentDisplayedGoals属性存储当前要展示的数据,同时把原始数据数组设为私有避免误修改:
final class HomeViewModel { weak var view: HomeScreenInterface? var progressSections: [String] = ["To Do","In Progress","Done"] // 私有原始数据,避免被外部修改 private lazy var toDoGoals: [ToDoModel] = [ ToDoModel(title: "ToDo 1"), ToDoModel(title: "Todo 2"), ToDoModel(title: "ToDo 3") ] private lazy var inProgressGoals: [ToDoModel] = [ ToDoModel(title: "Progress 1"), ToDoModel(title: "Progress 2"), ToDoModel(title: "Progress 3") ] private lazy var doneGoals: [ToDoModel] = [ ToDoModel(title: "Done 1"), ToDoModel(title: "Done 2"), ToDoModel(title: "Done 3") ] // 当前要显示的数组 var currentDisplayedGoals: [ToDoModel] = [] } extension HomeViewModel: HomeViewModelInterface { func viewDidLoad() { // 初始化默认显示ToDo数据 currentDisplayedGoals = toDoGoals view?.configureVC() view?.configureCollectionView() view?.configureTableView() view?.updateTableView() // 通知View更新初始数据 } func viewToDoGoals() { currentDisplayedGoals = toDoGoals view?.updateTableView() print("View todo") } func viewInProgressGoals() { currentDisplayedGoals = inProgressGoals view?.updateTableView() print("View progress") } func viewDoneGoals() { currentDisplayedGoals = doneGoals view?.updateTableView() print("View Done.") } }
2. 修改HomeScreenInterface
移除updateTableView的参数,因为不需要再传递数组:
protocol HomeScreenInterface: AnyObject { func configureVC() func configureCollectionView() func configureTableView() func updateTableView() }
3. 修改HomeScreen的updateTableView实现
不再修改viewModel.toDoGoals,直接刷新TableView:
extension HomeScreen: HomeScreenInterface { // ... 其他方法保持不变 func updateTableView() { DispatchQueue.main.async { self.goalsTableView.reloadData() } } }
4. 修改TableView数据源方法
改为使用currentDisplayedGoals作为数据源:
extension HomeScreen: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return viewModel.currentDisplayedGoals.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: GoalsCells.reuseIdentifier, for: indexPath) as? GoalsCells else { return UITableViewCell() } cell.delegate = self let goals = viewModel.currentDisplayedGoals[indexPath.row] cell.setGoalCell(goal: goals.title, checked: goals.isComplete) return cell } }
这样修改后,原始的三个数据数组始终保持初始状态,每次切换状态只是更新currentDisplayedGoals的值,切回“To Do”时会重新赋值原始的ToDo数据,TableView就能正常显示内容了。
内容的提问来源于stack exchange,提问作者Kerem DEMİR
相关产品推荐
相关产品推荐

