After successfully deleting a row from UITableView, I go to another view controller but when I return to the UITableView the deleted row is back again. Am I missing something? I am relatively new to Swift.
Here is the code:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
self.queuelayout.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
print(self.queuelayout)
}
return [delete]
}
I've also tried with this code:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
queuelayout.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .right)
}
}
Look forward to your help.
I checked your top codes. They are all right. The only possible reason is as you said you went to another VC , you have already get rid of your tableViewController from the memory. Here is an simple example:
If your tableView is the most right one, and when you go back to middle vc, your right one will be removed from the memory. Then when you click assign button and actually, you are loading a completely new tableViewController.
As a result, viewDidLoad will be called and your tableViewController will init again to the original states.
You may set a breakpoint at func viewDidLoad(), to check this situation. If this one is not called when you go back, you are good to go. Otherwise, everything will be reset. All what you delete will reappear as they should.
This is a simple example. Your case may be a little complicated. But if your tableviewcontroller called ViewDidLoad(), you must have some hassles somewhere.
Hope this help you out.
Related
I am trying enable editing of my UITableView by providing an Edit button on the nav bar.
The intention is to allow the user to insert new items and delete existing items.
When clicking the Edit button iOS shows the "Delete" decoration (deleting works fine), but doesnt show "Insert"
I have added navigationItem.rightBarButtonItem = editButtonItem to my UIViewControllers viewDidLoad and have added the following methods to my UITableViewDataSource delegate:
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
AppDelegate.persistenceContext.delete(self.fetchedResultsController.object(at: indexPath))
AppDelegate.saveContext()
} else if editingStyle == .insert {
let current = self.fetchedResultsController.object(at: indexPath)
// do rest of insertion logic
}
}
What am I missing something?
Oh and out of interest, if this is possible would the new cell be inserted above or below the one on which the action was initiated?
For the record I can add custom swipe actions to the cells, but the users feedback is they prefer an edit button.
Any light would be appreciated, all the Googling has gotten me is using a button to insert a new row, or adding custom swipe actions.
You need to implement the delegate method:
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle
Return .delete, .insert, or .none for a given index path. Normally only one row (typically first or last) would return .insert and the rest would return .delete. Return .none for any row that can't be inserted or deleted.
It's not uncommon that you also need to override the setEditing(_ editing: Bool, animated: Bool) method to add/remove an extra row just for the purposes of showing the green + (.insert) icon.
An alternative is to show the + icon in the nav bar instead of having a row with the insert icon.
I am showing a UITableView which is driven by RxRealmDataSources.
I need to perform some actions when a row in the table gets deleted.
Is there a way such that whenever a row gets deleted from the table, a function gets called with the indexpath of the deleted row?
Edit -
The UI of a cell of the UITableView in my app depends on 2 things -
A data object that is fetched from the realm db ( info )
The index position of the row
Whenever, a cell gets deleted, I need to update the UI of its next cell.
If the only way the db ever got updated was by the direct action of the user, then I could have used func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) method to get the indexPath of the cell that should be deleted and update the UI of the next cell.
However, the db is synced to cloud and the db is binded to the table view so that I do not have control on when cells gets added or deleted. It is for this reason, I wanted to know if there is a way to know when a cell is removed from UITableView
Due to the reusability of cells in UITableView, cells are not actually deleted until the table itself is deallocated.
I might assume that by 'deleting' cell you mean cell disappearing from the screen. In this case the following function of UITableViewDelegate might help you (called when the cell is not visible any more):
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
In a comment you said:
By 'deleting', I mean when the cell is removed from the tableview like when we swipe the cell to the left to remove it.
Since you tagged RxSwift, the solution is to use itemDeleted as in:
tableView.rx.itemDeleted
.subscribe(onNext: { print("delete item at index path \($0) from your model.")})
.disposed(by: bag)
If you aren't looking for an Rx solution, then your question is a dup of:
Add swipe to delete UITableViewCell
I was able to solve this by subclassing the UITableView class and overriding the func deleteRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation) method.
You have to implement 1 delegate method of UITableView.
trailingSwipeActionsConfigurationForRowAt
It's easy to implement. This delegate method will be called twice, one when you swipe and again when you press to delete a row.
`enter code here`
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let config = UISwipeActionsConfiguration(actions: [makeDeleteContextualAction(forRowAt: indexPath)])
config.performsFirstActionWithFullSwipe = true
return config
}
private func makeDeleteContextualAction(forRowAt indexpath:IndexPath) -> UIContextualAction {
let deleteAction = UIContextualAction(style: .destructive, title: LocalizableConstants.constLS_global_delete()) { (action, swipeButtonView, completion) in
let product = self.products[indexpath.row]
if let quantity = product.vo_quantity(), let amount = product.vo_priceFide() {
self.totalProducts -= Int(truncating: quantity)
self.totalAmount -= amount.doubleValue * quantity.doubleValue
}
DispatchQueue.main.async {
self.lbBasketNumber.text = String(self.totalProducts)
self.lbTotalAmount.text = String(self.totalAmount)
}
self.products.remove(at: indexpath.row)
self.tableView.deleteRows(at: [indexpath], with: .fade)
if #available(iOS 13.0, *) {
action.image = ImagesConstants.constIMG_XCA_mini_icon_red_trash()
action.image?.withTintColor(ConstantsColor.const_COLOR_RED())
action.backgroundColor = ConstantsColor.const_COLOR_WHITE()
} else {
action.title = LocalizableConstants.constLS_global_delete()
}
completion(true)
}
return deleteAction
}
My project contains a tableview. This tableview consists of 2 sections. The first section contains a single cell that is not editable. The second section is populated by an array called data.
There is a button that starts editing mode and allows the user to delete content from the second section.
I'm trying to end editing mode when the second section is empty so that i can select the cell in my first section.(aesthetic purposes)
My code looks like this (simplified, not actual code):
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
data.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
if(data.count==0) {
self.tableView.setEditing(false, animated: true)
self.tableView.selectRow(at: IndexPath(row: 0, section: 0), animated: false, scrollPosition: .top)
}
This leads to all kinds of weird bugs. Which, according to the documentation, is expected:
You should not call setEditing:animated: within an implementation of this method. If for some reason you must, invoke it after a delay by using the performSelector:withObject:afterDelay: method.
It works, but I feel like this would be a hacky solution. It is not clear to me why I should not end editing when everything is deleted. Can someone explain this? Or perhaps any alternatives?
I have 2 UITableView (Table-1 & Table-2) at same UIViewController. I want to editing functionality in my Table-2.
I have added tableview datasource method in my view controller as mentioned below: -
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
tableView.beginUpdates()
myArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()
}
}
and both tableview calling this method. So each tableview cells are able to open delete option.
But I want this delete editing option in only Table-2. I want to restrict delete editing option functionality in Table-1.
Please help. Thanks in advance.
You can use this function provided by UITableViewDelegate:
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
Simply implement some logic to check if you want to allow editing at the given indexPath and given tableView and return true if you want editing/deleting and return false if you don't.
Hope this helps!
like this
How can I have a swipe delete cell button like iOS mail application(image + text )?
I found this method but my image is not scale to size:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let deleteButton = UITableViewRowAction(style: .Destructive, title:"\nDelete", handler: { (action, indexPath) in
self.tableView.dataSource?.tableView?(self.tableView,commitEditingStyle: .Delete,
forRowAtIndexPath: indexPath)
return
})
deleteButton.backgroundColor = UIColor(patternImage: UIImage(named: "icon")!)
return [deleteButton]
}
thanks in advance
I am little confused with your explanation. If you can please provide some more explanation regarding button you want. Do you want Standard button which iOS provides itself or you want a customize button?
I am trying to address both aspects below.
If you need standard operation you can do it like this:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// remove the item from the array if you want
array.remove(at: indexPath.row)
// delete the table view row
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
}
Also, i would like to recommend This.
If u just want to resize button image you can do it like this:
deleteButton.imageView?.contentMode = UIViewContentMode.scaleAspectFill
The table view will do that for you. You just need to have your table view/table view controller live in a navigation stack so there's a navigation bar, and then implement a couple of methods: tableView(_, canEditRowAt:) and tableView(_:,commit:forRowAt:).
You'll probably want to add an edit button to your navigation bar.
I just pushed a demo project called MasterDetailSwift that supports adding and removing cells to a table view. (It also shows the master/detail UI pattern, a good way to handle prepareForSegue using a switch statements, and a few other useful techniques.)