delete section at indexPath swift - ios

I have an array which populates a table view - myPosts.
The first row of the table view is not part of the array.
Each row is its own section (with its own custom footer)
I am trying to perform a delete with the following code:
func tableView(profileTableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
myPosts?.removeAtIndex(indexPath.section - 1)
profileTableView.beginUpdates()
let indexSet = NSMutableIndexSet()
indexSet.addIndex(indexPath.section - 1)
profileTableView.deleteSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
profileTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
profileTableView.endUpdates()
...
WS Call
...
}
}
And the log is reporting the following:
Invalid update: invalid number of rows in section 0. The number of
rows contained in an
existing section after the update (1) must be equal to the number of rows contained in that
section before the update (1), plus or minus the number of rows inserted or deleted from
that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out
of that section (0 moved in, 0 moved out).'
Obviously the issue is related to 0 moved in, 0 moved out but I don't understand why that is? or what the solution would be?
Number of sections in tableView is as follows:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if self.myPosts == nil
{
return 1
}
return self.myPosts!.count + 1
}

Updated the answer for Swift 4.2 and made a few additional tweaks:
func tableView(_ tableView: UITableView,
commit editingStyle: UITableViewCell.EditingStyle,
forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
myPosts?.removeAtIndex(indexPath.section - 1)
let indexSet = IndexSet(arrayLiteral: indexPath.section)
profileTableView.deleteSections(indexSet, with: .automatic)
// Perform any follow up actions here
}
}
The use of beginUpdates() and endUpdates() is not necessary, since you are only doing one action that contains animation. If you are doing 2 or more, than it is worth combining them to get a fluid effect.
Also, this makes use of the Swift 3 classes, by doing away with the NSMutableIndexSet() call, which would require a conversion now to work with the deleteSections() call.

So the answer is just removing the line that deletes the rows.
So the code is here to delete:
func tableView(profileTableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
myPosts?.removeAtIndex(indexPath.section - 1)
profileTableView.beginUpdates()
let indexSet = NSMutableIndexSet()
indexSet.addIndex(indexPath.section - 1)
profileTableView.deleteSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
// profileTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
profileTableView.endUpdates()
...
WS Call
...
}
}

Related

Delete rows from tableview using swift

I make a table view on my application, I want to add option that could the user delete the row in tableview.
I'm using this func
h1 is my array string that I put it in tableview.
my error is when I'm try to delete row in func editinstyle
var h1:[String] = ["one","two","three"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
h1.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = self.tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath as IndexPath) as! TableView1
cell.information.text = h1[indexPath.row]
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
h1.remove(at: indexPath.row) //Remove element from your array
print(h1)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
when I try to click to Delete it show like this 2020-02-11 20:43:35.803024+0200 TraniersApp[13314:401189] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Does someone know where is the problem?
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)
Suspect this is a race condition that can be resolved by performing the h1.remove() and tableView.deleteRows() within a transaction (i.e., between tableView.beginUpdates() and tableView.endUpdates()).
tableView.beginUpdates()
h1.remove(at: indexPath.row) //Remove element from your array
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()

UITableView: Invalid update: invalid number of rows in section 0 [duplicate]

Swift 3.0 iOS 10.x
Using this code to try and delete a row in a table...
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}
This fails with the error message?
2017-05-29 13:36:23.843228+0200[939:576777] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (9) must be equal to the number of rows contained in that section before the update (9), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Which sounds fair enough only this is boiler plate code? I am doing little more than clicking on the red button?
Yes, there are 3 rows here... in my code that crashed there were 9.
What have I missed here? Printed out the returned indexPath here and indeed it was wrong, but wait I didn't set it. This method did?
DELETE [0, 3]
You must delete row in your data array before deleting in tableView
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
yourArray.remove(at: indexPath.row) /* delete in data array */
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}

NSInternalInconsistencyException tableView row deletion

Swift 3.0 iOS 10.x
Using this code to try and delete a row in a table...
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}
This fails with the error message?
2017-05-29 13:36:23.843228+0200[939:576777] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (9) must be equal to the number of rows contained in that section before the update (9), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Which sounds fair enough only this is boiler plate code? I am doing little more than clicking on the red button?
Yes, there are 3 rows here... in my code that crashed there were 9.
What have I missed here? Printed out the returned indexPath here and indeed it was wrong, but wait I didn't set it. This method did?
DELETE [0, 3]
You must delete row in your data array before deleting in tableView
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
print("DELETE \(indexPath)")
yourArray.remove(at: indexPath.row) /* delete in data array */
self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}

TableView row removal with NSFetchedResultsController crashing?

I'm trying to let users delete a row from a UITableView that's populated using a NSFetchedResultsController but keep getting a fatal error:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of rows in section 1. The number of rows contained in an
existing section after the update (7) must be equal to the number of
rows contained in that section before the update (7), plus or minus
the number of rows inserted or deleted from that section (0 inserted,
1 deleted) and plus or minus the number of rows moved into or out of
that section (0 moved in, 0 moved out).'
I'm deleting the core data entry and then deleting the row in the tableView in my code but still get the error above:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.feedTable.beginUpdates()
let event = self.fetchedResultsController.object(at: indexPath) as Event
self.managedObjectContext.delete(self.fetchedResultsController.object(at: indexPath))
do {
try self.managedObjectContext.save()
} catch {}
self.feedTable.deleteRows(at: [indexPath], with: .automatic)
self.feedTable.endUpdates()
}
}
Can anybody help understand what I'm doing wrong?
If you use a fetched results controller. Only delete the object with
self.managedObjectContext.delete(self.fetchedResultsController.object(at: indexPath))
Try this solution
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let event = self.fetchedResultsController.object(at: indexPath) as Event
self.managedObjectContext.delete(self.fetchedResultsController.object(at: indexPath))
do {
try self.managedObjectContext.save()
} catch {}
}
}
You don't need beginUpdates and endUpdates

Delete UITable sections dynamically with commitEditingStyle in Swift

I’m dealing with an issue I can’t work around… I have a table of names, from a DB-array of customers, every customer has a name property among other data members.
I can delete rows within a section successfully, but what I can’t do it's deleting the section (when the last row within that section gets deleted, section must disappear).
I got:
'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of sections. The number of sections contained in the table
view after the update (3) must be equal to the number of sections
contained in the table view before the update (4), plus or minus the
number of sections inserted or deleted (0 inserted, 0 deleted).
I know the table does some sanity checking behind the scenes of the data and this should match, but I can’t figurate exactly when, before calling deleteRowsAtIndexPaths? after? When should I update my property and/or dictionary? Should I manage numberOfSectionsInTableView data-source method?
I repeat, for rows deleting it’s working alright, the table moves out the row and gets updated properly. Last row on section is the deal...
I guess I'm missing something, that’s why I’m asking… Couldn’t find any help reading around either.
Thank you all very much!
func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
// handle delete (by removing the data from the array and updating the tableview)
//Check if delete was press
if editingStyle == .Delete {
//Delete row from dataSource
if let tv = tableView
{
customerList.removeAtIndex(returnPositionForThisIndexPath(indexPath, insideThisTable: tableView))
// Deletes the name of the customer from the customer list array, sorted by name
fillArrayOfNames()
//Fill the array of names for the sections-table, creating a dictionary with the name initials
//updated from the customer list array (below)
tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) //Crash in this line
tableView.reloadData()
}
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return dictionaryOfPatientsInitials.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var keysFromDictionary = dictionaryOfPatientsInitials.keys.array
keysFromDictionary.sort(<)
let keyByOrder = keysFromDictionary[section]
let arrayInThisSection = dictionaryOfPatientsInitials[keyByOrder]
return arrayInThisSection!.count
}
You're almost there but you are going to need a way of detecting that a section has vanished, and which one has gone at which point you can call deleteSections
Bracket the update section in a beginUpdate / endUpdate call but do NOT call reloadData (See the docs for those methods about it)
/**
remove customer from model layer
:param: index index of customer to remove
:returns: return section that was removed or nil if none was
*/
func removeCustomer(index:Int)->Int? {
var removedSectionOrNil:Int? = nil
//logic to remove customer, rebuild model and detect if section has gone also
return removedSectionOrNil
}
func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
// handle delete (by removing the data from the array and updating the tableview)
//Check if delete was press
if editingStyle == .Delete {
//Delete row from dataSource
if let tv = tableView
{
tv.beginUpdates()
let position = returnPositionForThisIndexPath(indexPath, insideThisTable: tableView)
let removedSection = removeCustomer(position)
tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) //Crash in this line
if let removedSection = removedSection {
tv.deleteSections(sections:NSIndexSet(index: removedSection) as IndexSet, withRowAnimation: .Automatic)
}
tv.endUpdates()
}
}
}
Without seeing the rest of your code , this should work but tableViews can be tricky when doing vanishing sections.
I am sitting with a similar issue - however I have approached the problem from a non-programming way.
What I have done is to have two tableviews one that simply list all "Customer" key's to their details. (I use a key in the dictionary which is written to the DB, and a second to list "customers" details - each customer is a section.
I have then used Checkmark in the key table as my editing accessory for the cell in the table. Using the delete option for editing will delete the key and then I then simply remove that dictionary item in this code:
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete
actDict[keyArray[indexPath.row]] = nil
keyArray.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
try! writeFile!.addValuesToUserFile(actDict)
}
}
This works flawlessly for me.
Sorry for the incomplete initial answer

Resources