Swift5 Get the "invalid number of rows in section" error when trying to delete a row in tableview (task manager with core data)

Viewed 12

Sirs! Trying to create the Task manager App with core data. I have an array with all done and current tasks. I divide it for two arrays to load a tableview (it shows either current tasks or tasks are done). When I'm trying to delete a task with swipe on the table, I receive "invalid number of rows in section" error. My code is below. Please advise how to fix it? My thanks in advance.

import UIKit
import Foundation

protocol TaskNotesDelegate: AnyObject {
    func refreshTasks()
    func deleteTask(with id: UUID)
}

class TasksViewController: UIViewController {
    
    @IBOutlet weak var doneTaskSwitcher: UIBarButtonItem!
    @IBOutlet weak var addTaskButton: UIBarButtonItem!
    static let identifier = "TasksViewController"
    let tableView: UITableView = {
        let tableView = UITableView()
        tableView.translatesAutoresizingMaskIntoConstraints = false
        return tableView
    }()
    let idTasksCell = "idTasksCell"
    //константа для реализации функции поиска через searc controllr
    let searchController = UISearchController(searchResultsController: nil)
    var allTasks: [Task] = [] 
   
    var doneTasks: [Task] = []
    var currentTask: [Task] = []
    private var filteredTasks: [Task] = []
    var currentSearch = ""
    var doneTasksCheck = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.separatorStyle = .none
        tableView.register(TaskTableViewCell.self, forCellReuseIdentifier: idTasksCell)
        configureSearchBar()
        setConstraints()
        fetchTasksFromStorage()
        
        for i in 0..<allTasks.count {
            if allTasks[i].taskIsDone {
                doneTasks.append(allTasks[i])
            } else {
                currentTask.append(allTasks[i])
            }
        }
        
        for i in 0..<allTasks.count {
            print("all \(allTasks[i].id)")
        }
        
    override func viewWillAppear(_ animated: Bool) {
        self.navigationController?.navigationBar.backgroundColor = .white
        self.tabBarController?.tabBar.backgroundColor = .white
        tableView.reloadData()
    }
    
    @IBAction func showDoneTasks(_ sender: UIBarButtonItem) {
        if doneTasksCheck == false {
            doneTasksCheck = true
            doneTaskSwitcher.title = "current"
            doneTasks = doneTasks.sorted { $0.taskDate > $1.taskDate }
            tableView.reloadData()
            addTaskButton.isEnabled = false
        } else {
            doneTasksCheck = false
            doneTaskSwitcher.title = "is done"
            tableView.reloadData()
            addTaskButton.isEnabled = true
        }
    }
    
    private func indexForTask(id: UUID, in list: [Task]) -> IndexPath {
        let row = Int(list.firstIndex(where: { $0.id == id }) ?? 0)
        return IndexPath(row: row, section: 0)
    }
    
    @IBAction func addTaskButton(_ sender: UIBarButtonItem) {
        goToEditTask(createTask())
    }
    
    private func goToEditTask(_ task: Task) {
        let controller = storyboard?.instantiateViewController(identifier: TaskDetailsViewController.identifier) as! TaskDetailsViewController
        controller.task = task
        controller.delegate = self
        navigationController?.pushViewController(controller, animated: true)
    }
    
    // MARK:- Methods to implement
    private func createTask() -> Task {
        let task = CoreDataManager.shared.createTask()
        
        // Update table
        allTasks.insert(task, at: 0)
        tableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .automatic)
        return task
    }
    
    private func fetchTasksFromStorage() {
        allTasks = CoreDataManager.shared.fetchTasks()
    }
    
    private func deleteTaskFromStorage(_ task: Task) {
        
        deleteTaskSviped(with: task.id)
        CoreDataManager.shared.deleteTask(task)
    }
    
}

//UITableViewDelegate, UITableViewDataSource
extension TasksViewController: UITableViewDelegate,UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if doneTasksCheck == true {
            if currentSearch == "" {
                filteredTasks = doneTasks.sorted { $0.taskDate > $1.taskDate }
            }
        } else {
            if currentSearch == "" {
                filteredTasks = currentTask.sorted { $0.taskDate < $1.taskDate }
            }
        }
        return filteredTasks.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: idTasksCell, for: indexPath) as! TaskTableViewCell
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd.MM.YYYY"
        cell.taskLabel.text = filteredTasks[indexPath.row].task
        cell.taskDateLabel.text = dateFormatter.string(from: filteredTasks[indexPath.row].taskDate)
        if filteredTasks[indexPath.row].taskDate < Date().onlyDate! {
            cell.taskDateLabel.textColor = .red
        } else {
            cell.taskDateLabel.textColor = .black
        }
        cell.taskTegLabel.text = filteredTasks[indexPath.row].taskTag
        if filteredTasks[indexPath.row].taskReminder != nil {
            cell.taskRemindTimeLabel.isHidden = false
            dateFormatter.dateFormat = "HH:mm"
            cell.taskRemindTimeLabel.text = dateFormatter.string(from: filteredTasks[indexPath.row].taskReminder!)
        } else {
            cell.taskRemindTimeLabel.isHidden = true
        }
        if filteredTasks[indexPath.row].taskNote == nil || filteredTasks[indexPath.row].taskNote == "" {
            cell.taskNoteLabel.isHidden = true
        } else {
            cell.taskNoteLabel.isHidden = false
        }
        if filteredTasks[indexPath.row].taskIsDone == false {
            cell.taskDoneButton.setBackgroundImage(UIImage(systemName: "circle"), for: .normal)
        } else {
            cell.taskDoneButton.setBackgroundImage(UIImage(systemName: "chevron.down.circle.fill"), for: .normal)
        }
        cell.layer.masksToBounds = true
        cell.layer.cornerRadius = 15
        cell.layer.borderWidth = 2
        cell.layer.borderColor = UIColor.white.cgColor
        cell.selectionStyle = .none
        cell.cellTaskDelegate = self
        cell.index = indexPath
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 75
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        goToEditTask(filteredTasks[indexPath.row])
    }
    
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            deleteTaskFromStorage(filteredTasks[indexPath.row])
        }
    }
    
}

extension TasksViewController {
    
    func setConstraints() {
        view.addSubview(tableView)
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
        ])
    }
    
}

// MARK:- TaskNotes Delegate
extension TasksViewController: TaskNotesDelegate {
    
    func refreshTasks() {
        allTasks = allTasks.sorted { $0.taskDate < $1.taskDate }
        currentTask = currentTask.sorted { $0.taskDate < $1.taskDate }
        tableView.reloadData()
    }
    
    func deleteTaskSviped(with id: UUID) {
        let indexPath = indexForTask(id: id, in: filteredTasks)
        filteredTasks.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .automatic)
        // just so that it doesn't come back when we search from the array
        allTasks.remove(at: indexForTask(id: id, in: allTasks).row)
    }
        
}
0 Answers
Related