I am working on a code where I have to insert & delete all rows on selecting a section.
Below is the code for inserting & deleting
var paths = [IndexPath]()
for row in 0..<(arrayOfSection?.count)! {
let indexPath = IndexPath(row: row, section: selectedIndex!)
paths.append(indexPath)
}
// Toggle collapse
if previousSelectedIndex != nil && previousSelectedIndex == section {
self.arrayOfCategories?.removeAll()
self.catergoryTableView.beginUpdates()
self.catergoryTableView.deleteRows(at: paths, with: .fade)
self.catergoryTableView.endUpdates()
}
else{
self.catergoryTableView.beginUpdates()
self.catergoryTableView.insertRows(at: paths, with: .fade)
self.catergoryTableView.endUpdates()
header.setCollapsed(false)
//scroll
let sectionRect = self.catergoryTableView.rect(forSection: selectedIndex!)
self.catergoryTableView.scrollRectToVisible(sectionRect, animated: true)
}
previousSelectedIndex = selectedIndex
Inserting rows works fine but when I am trying to delete rows from selected section in am getting below error
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 9 from section 0 which only contains 0 rows before the update'
What am I doing wrong?
Update your code to delete all row as follows:
self.catergoryTableView.beginUpdates()
self.catergoryTableView.deleteRows(at: paths, with: .fade)
self.catergoryTableView.endUpdates()
self.arrayOfCategories?.removeAll()
Just add first line of code to the last.
Related
I've implemented the following deleting mechanism: on delete action tableView deletes selected rows and if section does not have any rows it will be deleted.
My mechanism looks like this:
guard let selectedRows = self.tableView.indexPathsForSelectedRows,
let indexPath = self.tableView.indexPathForSelectedRow else { return }
self.tableView.beginUpdates()
self.dataSource[indexPath.section].rows.remove(at: indexPath.item)
if self.dataSource[indexPath.section].rows.isEmpty {
self.dataSource.remove(at: indexPath.item)
self.tableView.deleteSections(IndexSet(arrayLiteral: indexPath.section), with: .fade)
}
self.tableView.deleteRows(at: selectedRows, with: .fade)
self.tableView.endUpdates()
My dataSource object:
struct DataSource {
var section:String
var rows:[Row]
}
struct Row {
var data:String
}
The problem is when I select more than one row and try to delete selected rows I've got a crush with following message:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (5) must be equal to the number of rows contained in that section before the update (6), plus or minus the number of rows inserted or deleted from that section (0 inserted, 2 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
While I delete by one row my mechanism works fine, as expected. Even deletes an empty section. Any thoughts, where am I wrong? Thanks a lot.
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()
When I remove an object from a list and try to add a new one in I get this error
2020-01-24 14:40:26.692343+1300 HappyDays[25416:1017241] *** 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 (3) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
I see other issues similar to this but I've tried implementing those solutions . (Similar issue , another similar issue)
Sections of my code:
Selecting the cell to delete if from the table
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
activeObjectives.actives.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .left)
}
Adding a new object to the table by tapping a button
#IBAction func getGoals(_ sender: UIButton) {
let newRowIndex = activeObjectives.actives.count
activeObjectives.setRandomGoalToActive(allObjectiveList: allGoalsArray)
addActiveGoalToactiveObjectives()
let indexPath = IndexPath(row: newRowIndex, section: 0)
let indexPaths = [indexPath]
activeGoalDisplay.insertRows(at: indexPaths, with: .automatic)
}
In case it's also needed, here is my addActiveGoalToactiveObjectives function called in the above
func addActiveGoalToactiveObjectives() {
for goal in allGoalsArray.goalsList {
if goal.isActive == true && activeObjectives.actives.contains(goal) == false {
activeObjectives.actives.append(goal)
}
}
}
Thanks in advance, any help is greatly appreciated
I found the issue. I wasn't setting an object value to false when removing it from the list. Now when I remove them I set the object to inactive.
activeObjectives.actives[indexPath.row].setInactive()
activeObjectives.actives.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .left)
}```
I want to delete a row from a table view, but it isn't working :/
This next code block is triggered from a custom button (not from an internal Apple-Table-Edit).
self.tableView.beginUpdates()
self.sections[indexPath.section].items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
self.tableView.endUpdates()
This is how a section looks like:
class Section: Comparable {
var state: TrackingObject.stateEnum
var items: [TrackingObject]
var expanded: Bool
init(state : TrackingObject.stateEnum, items : [TrackingObject], expanded : Bool){
self.state = state
self.items = items
self.expanded = expanded
}
static func group(trackingObjects: [TrackingObject]) -> [Section] {
let groups = Dictionary(grouping: Model.trackingObjects) { (trackingObject: TrackingObject) -> TrackingObject.stateEnum in
return trackingObject.currentState
}
return groups.map { (state: TrackingObject.stateEnum, trackingObjects: [TrackingObject]) in
return Section(state: state, items: trackingObjects, expanded: state == .active_due ? true : false)
}.sorted()
}
}
Expected: That the row of the given indexPath is removed with an animation as well as removed in the 'data source' (called: self.sections)
Actual Output: Error-Message:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'attempt to insert row 2
into section 0, but there are only 0 rows in section 0 after the
update'
(I was removing the second row in the section 0)
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.
so I have an app with radiobuttons to check off tasks, everything's working as expected as long as I let the animation finish but if I press two buttons at the same time I get an error:
libc++abi.dylib: terminating with uncaught exception of type NSException
The Code executed every time a radiobutton is tapped
func RadioTapped(_ cell: TableViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
// Removes task from coreData
let task = self.tasks[indexPath.row]
print(tasks.count)
self.context.delete(task)
print(tasks.count)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
do{
self.tasks = try self.context.fetch(TodayTask.fetchRequest())
// Animates the removal of task cell
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800),execute: {
self.tableView.beginUpdates()
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
})
} catch {
print("Fetching Failed")
}
}
}
Error Message
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 (11) must be equal to the number of rows contained in that section before the update (13), 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).'
Table row delete operation also requires to delete element of array of table.
According to your code, self.tasks may be an array for your table list.
Delete an element of 'self.tasks' from same indexes, for which you are deleting your rows.
Hint:
// Remove array element
self.tasks.remove(at: <index.row>)
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(800),execute: {
self.tableView.beginUpdates()
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
})
I am writing an iOS app in Swift.
Whenever the page loads it gets the list of movies from server and it populates that list into tableView.
I wrote the code for getting JSON from server in a static library (Objective-C) and am receiving json to app via Notification design pattern.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ReceivedNListOfMoviesNotification(_:)), name: Notification.Name(VUSDK.basicNotificationName()), object: nil)
requestForData()
}
func ReceivedNListOfMoviesNotification(_ notification:NSNotification)
{
if let info = notification.userInfo {
basicArray=info["Search"] as! [Any]
if basicArray.count>0 {
tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath.init(row: self.basicArray.count-1, section: 0)], with: .automatic)
tableView.endUpdates()
}
}
}
But app is crashing:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3600.7.47/UITableView.m:1737
2017-04-23 13:49:12.562 VUDemo[4835:164247] *** 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 (10) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Replace
if basicArray.count>0 {
tableView.beginUpdates()
self.tableView.insertRows(at: [IndexPath.init(row: self.basicArray.count-1, section: 0)], with: .automatic)
tableView.endUpdates()
}
with
if !basicArray.isEmpty {
tableView.reloadData()
}
because you are overwriting the entire array rather than adding a single item.