【问题标题】:tableviewdeleterows crashing app even though data was updated即使数据已更新,tableviewdeleterows 也会导致应用程序崩溃
【发布时间】:2020-12-09 21:17:15
【问题描述】:

我目前有这段代码应该删除一个表格行。

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

我确保在删除行之前更改我的数据源

userHabitData.remove(at: indexPath.section)

但是代码还是会抛出这个错误

线程 1:“无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (1) 必须等于更新前该节中包含的行数 (1 ),加上或减去从该节插入或删除的行数(0 插入,1 删除),加上或减去移入或移出该节的行数(0 移入,0 移出)。"

这是我完整的视图控制器

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

任何帮助将不胜感激!

【问题讨论】:

  • 试试deleteSections(_:with:)而不是deleteRows
  • 你能试试self.userHabitData.remove(at: indexPath.section)吗?
  • 它仍然给我相同的结果,我做了一些调试,发现删除后的数组计数确实为 0,而在我删除行之前行计数为 1。我相信这应该是正确的输出,这让我更加困惑
  • 以下行没有意义。 userHabitData.remove(at: indexPath.section)
  • 另外,以下几行没有意义。让 dictKey = userHabitData[indexPath.section].getName();让 dictValue = userHabitData[indexPath.section].getCount()

标签: swift xcode


【解决方案1】:

问题是你的数据源不一致。

delete 方法中,数据源数组是userHabitData,但在numberOfSections 中,您使用的是UserHabitDict,它不会在删除操作中更新。

numberOfSections 替换为

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

然后删除部分(包括行)

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

请删除结构中的getNamegetCount 函数。它们是多余的。直接使用名称和计数成员。您还可以从名称中删除冗余信息习惯

【讨论】:

  • 非常感谢您的回复!我应用了更改,但不幸的是它仍然给了我相同的错误消息。我也想知道为什么你在 tableView.deleteSections 中有“at”,因为 xcode 给了我一个错误“Extraneous argument label 'at:' in call”不确定我是否在这里遗漏了什么
  • 我的错,删除at:。如果数据源数组一致,则代码应该可以工作。
  • 由于某种原因,我的代码在不使用 swipecellkit 的情况下运行良好,我使用了 UITableViewCell.EditingStyle,它运行良好!
猜你喜欢
  • 1970-01-01
  • 2017-01-19
  • 2017-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多