Don't Delete Some Rows from Uitableview

Don't delete some rows from UITableView

UITableView has a method exactly for this purpose called canEditRowAt. You just need to return false when indexPath.section == 0

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 
return indexPath.section != 0
}

How do I disable the delete operation for certain row in a UITableView?

Implement the -tableView:canEditRowAtIndexPath: method in your data source. Return NO for those rows.

Deleting a Row from a UITableView in Swift?

Works for Swift 3 and Swift 4

Use the UITableViewDataSource tableView(:commit:forRowAt:) method, see also this answer here:

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

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

Stop a tableView cell from being deletable?

One thing you could do is implement -tableView:canEditRowAtIndexPath: method in your code & return NO for the rows you want to deactivate deletion possibility.

How to restrict deleting rows in TableView only to certain users?

You can do something like this:

If you don't have a custom class for UITableViewCell:

override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
if owner[indexPath.row] == me {
return .Delete
}
else {
return .None
}
}

Or if you have a custom class for UITableViewCell then this:

override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
if (tableView.cellForRowAtIndexPath(indexPath) as! YourTableViewCell).owner == me {
return .Delete
}
else {
return .None
}
}

Deleting the bottom row of TableView

Edit 2

After some experimentation, it appears to be an issue with iOS 12 (at least, on my iOS 12.4 simulator and device).

This can be (somewhat) confirmed by

  • launch the default iPhone Reminders app
  • add a bunch of reminders (I just used A, B, C, etc...) so you have enough that scrolling is needed
  • scroll down to the last row
  • delete the last row

You'll see that the row deletion animation is faulty. In fact, deleting any row does not provide the smooth animation we see in iOS 13.

Doing some searching I find similar issues back with iOS 7 reportedly fixed in iOS 8+ ... so perhaps the same bug returned in one of the iOS 12 versions. You may be able to use one of those older work-arounds, but based on comments it was pretty hit-or-miss.

I still stand by my initial comment, though, that there is no reason for:

tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .fade)

to be called after the row deletion.


Original Answer

It sounds like you are doing too much...

This is all you should need to get the row to delete and the other rows to "slide down":

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
Results.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}

No need to reload the data.

See example here: https://imgur.com/a/JvDQ1P6


Edit

Here is a complete (very simple) example. No @IBOutlet or @IBAction connections... just add a new table view controller to your Storyboard and assign its custom class to SampleTableViewController:

class SampleCell: UITableViewCell {

let testView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .blue
return v
}()
let testLabel: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}

@objc
func commonInit() -> Void {

contentView.addSubview(testView)
contentView.addSubview(testLabel)
let g = contentView.layoutMarginsGuide

// avoid constraint warnings
let c = testView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0)
c.priority = UILayoutPriority(rawValue: 999)

NSLayoutConstraint.activate([

c,
testView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
testView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
testView.heightAnchor.constraint(equalToConstant: 50.0),
testView.widthAnchor.constraint(equalTo: testView.heightAnchor),

testLabel.leadingAnchor.constraint(equalTo: testView.trailingAnchor, constant: 12.0),
testLabel.centerYAnchor.constraint(equalTo: testView.centerYAnchor),
testLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),

])

}

}

class SampleTableViewController: UITableViewController {
var data: [String] = []

override func viewDidLoad() {
super.viewDidLoad()

// fill data array with 30 strings
data = (1...30).map { "This is row \($0)" }

tableView.register(SampleCell.self, forCellReuseIdentifier: "SampleCell")
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) as! SampleCell
c.testLabel.text = data[indexPath.row]
return c
}

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
data.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
}

uitableview cell still doesn't delete properly the first time

Per @dante comment, the method in the description works for now, however:

  • Currently, the code above reloads the table view before either of those functions are completed.

  • As @jnpdx mentioned, the right approach would be to wait for the deletion to end before reloading the table view because deleteIndex.deleteObject and document(...).delete are both asynchronous functions.

Error when Removing Row from TableView (Swift)

self.sections[indexPath.section].items.remove(at: indexPath.row)
self.tableView.beginUpdates()
DispatchQueue.main.async {
tableView.deleteRows(at: [indexPath], with: .automatic)
self.tableView.endUpdates()
}

Try removing item from your data source before beginUpdates(). You can also just remove item from the data source and reload the table view as you are setting the animation option as automatic, so tableview will perform the preferable animation.



Related Topics



Leave a reply



Submit