Reputation: 656
I currently have this block of code that should delete a table row.
extension HomeController: SwipeTableViewCellDelegate {
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
print("in delete")
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { [self] action, indexPath in
print("currently deleting")
userHabitData.remove(at: indexPath.section)
tableView.deleteRows(at: [indexPath], with: .fade)
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete")
return [deleteAction]
}
I made sure to change my data source before deleting the row with
userHabitData.remove(at: indexPath.section)
However the code still throws this error
Thread 1: "Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out)."
Here is my complete view controller
//
// ViewController.swift
// Habit Tracker
//
// Created by Alan Weng on 11/24/20.
//
import UIKit
import SwipeCellKit
class tableViewCell: SwipeTableViewCell {
@IBOutlet weak var habitName: UILabel!
@IBOutlet weak var habitCount: UILabel!
var habit: Habit? {
didSet {
self.updateUI()
}
}
func updateUI() {
print("being run")
habitName?.text = habit?.title
habitCount?.text = habit?.detail
// progressLabel?.observedProgress = habit?.progress
}
}
class HomeController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var deno_label: UILabel!
@IBOutlet weak var tableView: UITableView!
let impactFeedbackgenerator = UIImpactFeedbackGenerator(style: .heavy)
@IBOutlet weak var deno_img: UIImageView!
var UserHabitDict: [String:String] = [:]
var userHabitData = [HabitDict]()
var userHabitName: String?
var userHabitCount: String?
let cellReuseID = "habitName"
let cellSpacingHeight: CGFloat = 15
let customRed = UIColor().customRed()
let customBlue = UIColor().customBlue()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
}
@IBAction func createNewGoal(_ sender: Any) {
let goalVC = storyboard?.instantiateViewController(withIdentifier: cellReuseID) as! CreateGoalController
impactFeedbackgenerator.prepare()
impactFeedbackgenerator.impactOccurred()
goalVC.habitDelegate = self
present(goalVC, animated: true, completion: nil)
}
// Think of how ios settings have different sections w diff spacings
func numberOfSections(in tableView: UITableView) -> Int {
return UserHabitDict.count
}
// Adjusts cell spacing between habits
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return cellSpacingHeight
}
// Adjust row height
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
// Allows the table to keep expanding based on how many habits are in the array
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
// Make the background color show through
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = UIColor.clear
return headerView
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if habitIsEmpty() {
deno_img.alpha = 0.0
deno_label.alpha = 0.0
}
print("making habit")
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseID) as! tableViewCell
let dictKey = userHabitData[indexPath.section].getName()
let dictValue = userHabitData[indexPath.section].getCount()
cell.delegate = self
cell.backgroundColor = customBlue
cell.layer.cornerRadius = 10
cell.habit = Habit(title: dictKey, detail: dictValue)
print(userHabitData)
return cell
}
func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
var options = SwipeOptions()
options.expansionStyle = .destructive
options.transitionStyle = .border
return options
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// note that indexPath.section is used rather than indexPath.row
// print("You tapped cell number \(indexPath.section).")
// let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseID) as! tableViewCell
// cell.habit?.updateDetail()
// tableView.reloadData()
// let dictKey = userHabitData[indexPath.section].getName()
// var dictValue = userHabitData[indexPath.section].getCount()
// print("over here")
// dictValue = String(Int(dictValue)! - 1)
// print(dictValue)
// cell.habit = Habit(title: dictKey, detail: dictValue)
// tableView.reloadData()
}
func allowMultipleLines(tableViewCell: UITableViewCell) {
tableViewCell.textLabel?.lineBreakMode = .byWordWrapping
}
func habitIsEmpty() -> Bool {
if userHabitData.isEmpty {
return false
} else {
return true
}
}
}
extension HomeController: CreateGoalDelegate {
func didTapSave(name: String, count: String) {
userHabitName = name
userHabitCount = count
UserHabitDict[name] = count
userHabitData.append(HabitDict(habitName: name, habitCount: count))
// tableView.insertRows(at: [IndexPath(row: userHabitData.count, section: 0)], with: .automatic)
tableView.reloadData()
print("in reload data")
}
}
extension UIColor {
func customRed() -> UIColor {
return UIColor(red: 0.607, green: 0.160, blue: 0.282, alpha: 1.00)
}
func customBlue() -> UIColor {
return UIColor(red: 0.509, green: 0.701, blue: 0.964, alpha: 1.00)
}
}
struct HabitDict {
let habitName: String
let habitCount: String
func getName() -> String {
return habitName
}
func getCount() -> String {
return habitCount
}
}
extension HomeController: SwipeTableViewCellDelegate {
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
print("in delete")
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { [self] action, indexPath in
print("currently deleting")
userHabitData.remove(at: indexPath.section)
tableView.deleteRows(at: [indexPath], with: .fade)
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete")
return [deleteAction]
}
}
any help would be greatly appreciated!!
Upvotes: 0
Views: 78
Reputation: 285082
The problem is that your data source is inconsistent.
In the delete
method the data source array is userHabitData
however in numberOfSections
you are using UserHabitDict
which is not being updated in the delete action.
Replace numberOfSections
with
func numberOfSections(in tableView: UITableView) -> Int {
return userHabitData.count
}
and then delete the section (including the row)
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { [self] action, indexPath in
print("currently deleting")
userHabitData.remove(at: indexPath.section)
tableView.deleteSections([indexPath.section], with: .fade)
}
And please remove the getName
and getCount
functions in the struct. They are redundant. Use the name and count members directly. And you could remove also the redundant information Habit from the names
Upvotes: 1