I am trying to remove a item from my TableView but when I swipe to left and click in Delete, I got this error:
This is the code that I have, when I comment the self.tableView.deleteRowsAtIndexPaths line, everything works fine for me.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
if let index: NSIndexPath = indexPath {
self.tableView.beginUpdates()
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
self.configurations.delete(ProductDatabase.deleteProduct(self.products[index.row]))
loadProductsToListOrder()
self.tableView.endUpdates()
}
} 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
}
}
I searched and found here on stack overflow about this beginUpdates and endUpdates.
Thank you.
Update
loadProductsToListOrder function
func loadProductsToListOrder() {
self.products = ProductDatabase.listProduct(self.configurations.db!)
self.tableView.reloadData()
}
If I have one element in my TableView, I do not have this problem. Just happen if I have more than one itens in my TableView.
Update 2
The answer that #harshayarabarla gave works for me, because I was forgetting to add the self.products.removeAtIndex(indexPath.row) before the deleteRowsAtIndex.
Thanks!
You need to remove the object from your datasource of the table view before you perform self.tableView.deleteRowsAtIndexPaths. later you can call self.tableView.reloadData method instead of begin updates and end updates. It's not necessary to call reloadData method though, as self.tableView.deleteRowsAtIndexPaths takes care of reloading thing.
if you call self.tableView.deleteRowsAtIndexPaths before making changes to dataSource of the table view you might face this error.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
if let index: NSIndexPath = indexPath {
self.configurations.delete(ProductDatabase.deleteProduct(self.products[index.row]))
self.products.removeAtIndex(index.row)
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
loadProductsToListOrder() // you can comment this if you are not adding any new items to products array
}
} 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
}
}
See Delete Data from Coredata Swift for full history.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
switch editingStyle {
case .Delete:
// remove the deleted item from the model
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
context.deleteObject(myData[indexPath.row] as NSManagedObject)
myData.removeAtIndex(indexPath.row)
context.save(nil)
//tableView.reloadData()
// remove the deleted item from the `UITableView`
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
default:
return
}
}
Also need was these two lines of code to be corrected.
var myData: Array<AnyObject> = []
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
Related
I'm having trouble removing the last cell I have tried tableView.reloadData() and beginUpdate(), endUpadate(), and all these methods works fine if I have more than one cell, but when I come to deleting the last cell it didn't work and the tableView won't reloadData at the same time that I delete the last cell, other cells 2-3-4 no problem, Plus when I close the app everyThing works fine.
im deleting the cells from the firebase store its a document that contains data if concern
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.DriverOffers.remove(at: indexPath.row)
self.DriverOrdersTV.deleteRows(at: [indexPath], with: .automatic)
self.DriverOrdersTV.reloadData()
}else if editingStyle == .insert {
self.DriverOrdersTV.beginUpdates()
self.DriverOrdersTV.insertRows(at: [IndexPath.init(row: 0, section: 0)], with: .automatic)
self.DriverOrdersTV.endUpdates()
}
}
Basically to delete the cell "offline" I use this method so that whenever you swipe from right to left the user can delete the tableview cell.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
self.polls.remove(at: indexPath.row)
}
}
However, it obviously doesn't affect the CKRecord of the cell content I created before. So how can I fetch and delete the CKRecord data at the exact row the user swiped-to-delete on?
Assuming polls is the data source array declared as [CKRecord] you have to do three things.
Get the record from the data source array at the given index and remove it from the appropriate CKDatabase.
Remove the record from the data source array (you're already doing that).
Delete the row in the table view calling deleteRowsAtIndexPaths passing [indexPath].
For example (publicDatabase is the actual CKDatabase instance):
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let record = polls[indexPath.row]
publicDatabase.deleteRecordWithID(record.recordID, completionHandler: ({returnRecord, error in
// do error handling
})
polls.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
Edit:
For proper error handling you might have to put the code of step two and three into the completion block.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let record = polls[indexPath.row]
publicDatabase.deleteRecordWithID(record.recordID, completionHandler: ({returnRecord, error in
if error != nil {
// do error handling
} else {
self.polls.removeAtIndex(indexPath.row)
dispatch_async(dispatch_get_main_queue()) {
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
})
}
}
I need to create a action in editActionsForRowAtIndexPath to delete a row in a table. Following some research on the internet I came to this code:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let remove = UITableViewRowAction(style: UITableViewRowActionStyle.Destructive, title: "Remover", handler: { (action: UITableViewRowAction, indexPath: NSIndexPath) -> Void in
self.tableData.removeObjectAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
})
return [remove]
}
but now I get this error
UITableView internal bug: unable to generate a new section map with
old section count: 1 and new section count: 0
When you delete a row from UITableView, you need to take care of two things.
First you should call tableView.deleteRowsAtIndexPaths only after you remove the object from the data source already. Because it'll check for the count again and ensure that the resultant data source have one less value.
Now the second thing to remember is that the no. of section can't be 0 after you delete the last row. If you are returning 0 to numberOfSectionsInTableView, return 1 at least on empty row count. Another option is to actually delete the index too when you delete the last row.
You don't need to use 'editActionsForRowAtIndexPath' method unless you implement your own custom accessory view but other wise you can use the standard swipe left gesture to delete rows and the delegate called is commitEditingStyle
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
tableData.removeObjectAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
else if editingStyle == .Insert {
//edit cell
}
}
//change the default 'Delete' text
override func tableView(tableView: UITableView, titleForDeleteConfirmationButtonForRowAtIndexPath indexPath: NSIndexPath) -> String? {
return "Show this instead of delete"
}
Do deleteRowsAtIndexPaths or reloadData, but not both.
What I have is a table view with different cells that display different messages with other people you're chatting with. Upon swiping the cell to the left, a Delete option shows up. I want to be able to delete both the cell itself as well as the Room associated with it in Parse. This is what I have so far:
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
//Delete messages here
let query = PFQuery(className: "Message")
query.whereKey("Room", equalTo: ??????)
tableView.beginUpdates()
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
tableView.endUpdates()
}
}
This function displays the Delete option, and when I click it, I want it to delete the cell it was clicked in. Does anyone know what goes inside the query? I have a Message class and I want to delete the Room key that's associated with the cell I delete.
Try this :
var dataToDelete:NSMutableArray = [] // this is a dummy array just to replicate your array
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
var object = dataToDelete[indexPath.row] as! PFObject
tableView.beginUpdates()
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
tableView.endUpdates()
object.delete()
}
}
I want to let the user of my App delete items from the NSUserDefaults out of a tableView by swiping left on the Cell and press "delete". I know both function but I don't know how to bring them together in the right was so that the "remove swipe" affects the variable in NSUserDefaults. Maybe someone can help me out. Thank you.
This function should allow the User to access the delete Button in a tableView:
func tableView(tableView: UITableView!, canEditRowAtIndexPath indexPath: NSIndexPath!) -> Bool {
return true
}
func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
if (editingStyle == UITableViewCellEditingStyle.Delete)
}
and the function should remove items from NSUserDefaults:
#IBAction func deleteItem(sender: AnyObject) {
var userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var itemListArray:NSMutableArray = userDefaults.objectForKey("itemList") as NSMutableArray
var mutableItemList:NSMutableArray = NSMutableArray()
for dict:AnyObject in itemListArray{
mutableItemList.addObject(dict as NSDictionary)
}
mutableItemList.removeObject(toDoData)
userDefaults.removeObjectForKey("itemList")
userDefaults.setObject(mutableItemList, forKey: "itemList")
userDefaults.synchronize()
}
First, let's change mutableItemList to an instance variable, which we'll use as the table's data source. Or, you can create a new instance variable and set it accordingly.
var mutableItemList: NSMutableArray!
Then, to delete we call the deleteItem function.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
self.deleteItem(mutableItemList[indexPath.row])
// show fancy fade animation to remove the cell from the table view
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
You can also simplify the deleteItem function. You don't need to rebuild the array and remove the object from NSUserDefaults. You can just delete the object and then set the updated array, which overwrites whatever was there.
func deleteItem(sender: AnyObject) {
mutableItemList.removeObject(sender)
var userDefaults:NSUserDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(mutableItemList, forKey: "itemList")
userDefaults.synchronize()
}