简体   繁体   中英

ios application crashes when deleting line in uitableView

I have a problem in my UITableView which filled with data: [(gamme: String, [(product: String, quantity: Double)])] , everything works fine: inserting rows and sections, deleting row and section, reloading. But sometimes and when I try to delete lots of lines in fast way (line by line by swiping the line the table and tap (-) ). it leads to a crash like in the screenshot.

The issue is hard to reproduce in development app. but my clients still reports it. My clients are professionals (not normal users) and are expected to use the in a fast way with medium to large data.

在此处输入图片说明

and this is my func that delete lines:

    override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    let delete = UITableViewRowAction(style: .destructive, title: "-") { (action, indexPath) in

        let cmd = self.groupedData[indexPath.section].1.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .right)
        self.delegate?.didDeleteCmdLine(cmd)

        if self.groupedData[indexPath.section].1.count == 0 {
            self.groupedData.remove(at: indexPath.section)
            tableView.deleteSections(IndexSet(integer: indexPath.section), with: UITableViewRowAnimation.right)
        }
    }

    return [delete]
}

why is that happening ?

This is a screen of xcode organiser for the crash

在此处输入图片说明 Edit:

Checking if groupedData is accessed by any thread other than main proposed by @Reinhard:

private var xgroupedData = [(gamme: GammePrdCnsPrcpl, [cmdline])]()

private var groupedData: [(gamme: GammePrdCnsPrcpl, [cmdline])] {
    get {
        if !Thread.isMainThread {
            fatalError("getting from not from main")
        }
        return xgroupedData
    }
    set {
        if !Thread.isMainThread {
            fatalError("setting from not from main")
        }
        xgroupedData = newValue
    }
}

but the groupedData variable is accessed only from main thread

tableView.beginUpdates()
self.tableView.deleteRows(at: [indexPath], with: .automatic)
tableView.endUpdates()

Changes in João Luiz Fernandes answer....try this

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
                if editingStyle == .delete {
                    objects.remove(at: indexPath.row)
                    tableView.deleteRows(at: [indexPath], with: .fade)
                } else if editingStyle == .insert {
                    // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
                }
            }

reference (Hacking with swift . https://www.hackingwithswift.com/example-code/uikit/how-to-swipe-to-delete-uitableviewcells )

try to use like this function.

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        print("Deleted")

        // do your delete your entires here..
        //

        self.tableView.deleteRows(at: [indexPath], with: .automatic)
    }
}

u can try this

         var myDataArray = ["one","two","three"]
         //wanna insert a row then in button action or any action write
         myDataArray.append("four")
         self.tblView.reloadData()
         // wanna delete a row
         myDataArray.removeObject("two")
         // you can remove data at any specific index liek
         //myDataArray.remove(at: 2)
         self.tblView.reloadData()

After the user tapped the delete button, you remove the corresponding row and (if this was the last row of that section) the corresponding section from your data source groupedData , which is an array. However, array operations are not thread-safe .
Can it be that another thread is using this array while it is modified by the delete action? In this case, the app can crash. The danger is of course higher, when several actions are triggered in a short time, which seems to be the case as you described it.
One way (maybe not the best) to avoid multithreading problems is to access the array only on the main thread.
If this slows down the main thread, one can use a synchronised array that allows multiple reads concurrently, but only a single write that blocks out all reads, see here .

There is just a update @codeByThey's answer.

Please Update your DataSource file as you delete that particular row.

tableView.beginUpdates()
self.whatEverDataSource.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
tableView.endUpdates()

This will result that your DataSource is also update same time as the TableView. The crash is happening may be due to the DataSource is not updated.

Can you try removing the section at once instead of trying to remove the row once, and then the section which it belongs to, when the last item in a section is being removed?

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    let delete = UITableViewRowAction(style: .destructive, title: "-") { [weak self] (action, indexPath) in

        // Use a weak reference to self to avoid any reference cycles.
        guard let weakSelf = self else {
            return
        }

        tableView.beginUpdates()

        let cmd: cmdline
        if weakSelf.groupedData[indexPath.section].1.count > 1 {
            cmd = weakSelf.groupedData[indexPath.section].1.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .right)
        } else {
            // Remove the section when the `items` are empty or when the last item is to be removed.
            cmd = weakSelf.groupedData.remove(at: indexPath.section).1[indexPath.row]
            tableView.deleteSections([indexPath.section], with: .right)
        }
        weakSelf.delegate?.didDeleteCmdLine(cmd)

        tableView.endUpdates()
    }

    return [delete]
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM