Search code examples
swiftuitableviewdelegatesdelete-row

How to delete a cell in the tableview from another View controller?


I am trying to delete a cell in the tableview from another view controller. I have modeled my code similar to the question posted below but I still can't seem to successfully delete the selected row/cell in the CalorieVC when the delete button is pressed in the DeleteVC

Deleting a row of a tableview from another viewcontroller

SideNote: there is button in the cells to popup the DeleteVC, I am also getting an error upon pressing the the deleteBtn in the CalorieVC: DeleteRowInTableviewDelegate on let picked saying Thread 1: Fatal error: Index out of range

Deleting cell

import UIKit

class CalorieViewController: UIViewController {

    var selectedFood: FoodList!       // allows data to be passed into the CalorieVC
    var deleteItems: CalorieItem?              // passes data to DeleteVC

    // allows data to be sepearted into sections
    var calorieItems: [CalorieItem] = []
    var groupedCalorieItems: [String: [CalorieItem]] = [:]
    var dateSectionTitle: [String] = []

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        tableView.dataSource = self
        tableView.delegate = self

        // Allows data in cells to seperate by section
        groupedCalorieItems = Dictionary(grouping: calorieItems, by: {$0.foodList.date})
        dateSectionTitle = groupedCalorieItems.map{$0.key}.sorted()
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "DeleteSegue" {
        let vc: DeleteViewController = segue.destination as! DeleteViewController
            vc.deleteItems = self.deleteItems
       //     vc.delegate = self

        }
    }
}

extension CalorieViewController: UITableViewDelegate, UITableViewDataSource{

    func numberOfSections(in tableView: UITableView) -> Int {
        return dateSectionTitle.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let date = dateSectionTitle[section]
        return groupedCalorieItems[date]!.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let calorieCell = tableView.dequeueReusableCell(withIdentifier: "CalorieCell") as! CalorieCell

        let date = dateSectionTitle[indexPath.section]
        let caloriesToDisplay = groupedCalorieItems[date]![indexPath.row]
        calorieCell.configure(withCalorieItems: caloriesToDisplay.foodList)

        return calorieCell
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let calorieHeader = tableView.dequeueReusableCell(withIdentifier: "CalorieHeader") as! CalorieHeader

        let headerTitle = dateSectionTitle[section]
        calorieHeader.dateLbl.text = "Date: \(headerTitle)"
        return calorieHeader
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 45
    }

    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let calorieFooter = tableView.dequeueReusableCell(withIdentifier: "CalorieFooter") as! CalorieFooter

        //Cell Total Code
        let date = dateSectionTitle[section]
        let subtotal = groupedCalorieItems[dispensary]?.map { $0.getCalorieTotal() }.reduce(0, +) ?? 0
        calorieFooter.calorieTotal.text = String(subtotal!)

        return calorieFooter
    }

    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 150
    }

}

extension CalorieViewController: DeleteRowInTableviewDelegate {
    func deleteRow(inTableview rowToDelete: Int) {
        let picked = dateSectionTitle[rowToDelete]
        let selectedCell = groupedCalorieItems[dod]
        delete(selectedCell)
      //  calorieItems.remove(at: rowToDelete)  // tried using this and I get an error code upon segueing back to the CalorieVC
        tableView.reloadData()
    }
}

import UIKit

protocol DeleteRowInTableviewDelegate: NSObjectProtocol {
    func deleteRow(inTableview rowToDelete: Int)
}

class DeleteViewController: UIViewController {

    var modifyItems: CartItem!
    var delegate: DeleteRowInTableviewDelegate?

    @IBOutlet weak var deleteLbl: UILabel!  
    @IBOutlet weak var deleteBtn: UIButton!
    @IBOutlet weak var cancelBtn: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        if isMovingFromParent {
            delegate!.deleteRow(inTableview: 1)
        }
        deleteLbl.text = "Are you sure you want to delete this Food Item from your calorie List?"
    }    

    @IBAction func decline(_ sender: Any) {
        dismiss(animated: true)
        delegate!.deleteRow(inTableview: 1)
        print("Delete Item")
    }

    @IBAction func cancel(_ sender: Any) {
        dismiss(animated: true)
        print("Cancel Delete")
    }
}

Solution

    1. Remove the value from the dataSource
    2. Remove the table cell

      extension CalorieViewController: DeleteRowInTableviewDelegate {
        func deleteRow(inTableview rowToDelete: Int) {
          if caloriesItems.count > rowToDelete {
            calorieItems.remove(at: rowToDelete)
            tableView.deleteRows(at: [IndexPath(row: rowToDelete, section: 0)], with: .automatic)
          } else { 
              print("index not present")
            }
        }
      }
      

    Do not call reloadData just to delete one row. This is a bad practice. Use deleteRows instead.