arraysswiftuitableviewuicollectionviewuikit

Not displaying in array transitions in Tableview


At the beginning of the application, I can successfully see the todo array. However, after moving a todo item to the "in progress" or "done" status, when I return to the "todo" status again, the todoGoals array is not visible on the screen. Only the section I last clicked on is visible.

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.")
    }
}

Home Screen : The protocol function where I update the tableview is here.

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 Delegate and DataSource Methods:

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 Delegate and DataSource Methods:

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
        }
    }

}

Model :

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)
    }
}

Pictures : 1-)Application opening and the selected ToDo state. 2-) The state where InProgress is selected. 3-) The state where Done is selected. 4-) Again, the state where ToDo is selected.


Solution

  • This is because with your current logic, whenever a user taps on "In Progress" or "Done" cell, that tapping event overwrites toDoGoals property.

    extension HomeScreen: HomeScreenInterface {
        //...
        // Update TableView Array
        func updateTableView(with goals: [ToDoModel]) {
            viewModel.toDoGoals = goals // Here: toDoGoals is updated every time user taps on other cells.
            DispatchQueue.main.async {
                self.goalsTableView.reloadData()
            }
        }
      }
    }
    

    So the original elements inside toDoGoals array are eliminated by tapping other cells. I think you can handle this issue in two ways.

    1. You can make another array variable to store items that you want to show on the tableview.
    2. Or you can leverage enum to indicate what type of tasks you want to show and let the table view show the relevant [ToDoModel] property.

    Hope this can help you to debug this issue!