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)
}
}
Delete rows from tableview using swift
To define "[indexPath]". It becomes [IndexPath(row: indexPath.row, section: 0)]
tableView.deleteRows(at: [IndexPath(row: indexPath.row, section: 0)], with: .automatic)
or
recall the particular section in the table view also
This will work outside of the function
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
How do I delete rows from a tableview in the context of a core data one to many relationship? (Swift)
I solved the issue:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
let itemsOnListArray = myFetchRCTripName!.itineraries?.allObjects
let obj = itemsOnListArray?[indexPath.row] as! Itinerary
myFetchRCTripName!.removeFromItineraries(obj)
tableView.deleteRows(at: [indexPath], with: .automatic)
CoreDataStack.shared.saveContext()
}
}
UITableView Delete Row
This is because your numberOfRowsInSection
data source implementation always returns 1 (fixed).
Typically, you store objects in an array, which defines the number of rows. And, commitEditingStyle
should remove the object from the array and then delete the row.
– (void)tableView: (UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath: (NSIndexPath *)indexPath {if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[maTheData removeObjectAtIndex:[indexPath row]];
// Delete row using the cool literal version of [NSArray arrayWithObject:indexPath]
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
Follow this link for more details.
Tableview deleting rows and sections
Solution: just add inverted indexPath array. let invertedIndexPathes = selectedRows.sorted(by: >)
Fixed mechanism:
guard let selectedRows = self.tableView.indexPathsForSelectedRows,
let indexPath = self.tableView.indexPathForSelectedRow else { return }
let invertedIndexPathes = selectedRows.sorted(by: >)
self.tableView.beginUpdates()
for itemIndexPath in invertedIndexPathes {
self.dataSource[itemIndexPath.section].rows.remove(at: itemIndexPath.row)
self.tableView.deleteRows(at: [itemIndexPath], with: .fade)
self.tableView.reloadData()
}
if self.dataSource[indexPath.section].rows.isEmpty {
self.dataSource.remove(at: indexPath.item)
self.tableView.deleteSections(IndexSet(arrayLiteral: indexPath.section), with: .fade)
}
self.tableView.endUpdates()
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)
}
}
}
Remove Row From Section
/// This line
sectionArray.remove(at: indexPath.row)
/// should be like this
sectionArray.remove(at: indexPath.section)
/// This line will remove the section from the table
tableView.deleteSections(.init(integer: indexPath.section), with: .automatic)
You are using row to remove a section
Edit
Replace all the code you provided us with this
/*
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
sectionArray[indexPath.section].remove(at: indexPath.row)
if sectionArray[indexPath.section].title.count == 0 {
sectionArray.remove(at: indexPath.row)
}
tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
}
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .normal, title: "Delete") { action, index in
//self.isEditing = false
print("delete button tapped")
}
delete.backgroundColor = UIColor.red
return [delete]
}
*/
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .normal, title: "Delete") { action, index in
//self.isEditing = false
sectionArray[indexPath.section].remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
if sectionArray[indexPath.section].items.isEmpty {
sectionArray.remove(at: indexPath.section)
tableView.deleteSections(.init(integer: indexPath.section), with: .automatic)
}
}
delete.backgroundColor = UIColor.red
return [delete]
}
Related Topics
Inter-App Data Migration (Migrating Data to New App Version)
How to Update the Constant Height Constraint of a Uiview Programmatically
Rounding a Double Value to X Number of Decimal Places in Swift
Protocol Doesn't Conform to Itself
Swiftui: How to Make Textfield Become First Responder
Waiting Until the Task Finishes
Passing an Array to a Function With Variable Number of Args in Swift
How to Enumerate an Enum With String Type
Is Swift Pass by Value or Pass by Reference
How Does One Generate a Random Number in Swift
Difference Between 'Let' and 'Var' in Swift
Nsdate() or Date() Shows the Wrong Time
How to Check If a String Contains Another String in Swift
Structure VS Class in Swift Language