I get a NSInternalInconsistencyException exception. It says : '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 (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).
It says before the update numberOfRowsInSection was 1, but it is not how I can see during debugging. Before the update, last time when numberOfRowsInSection was called it returned 0.
Do you have any idea?
this is what I see:
numberOfRowsInSection return 0
self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
numberOfRowsInSection get called and return 1
crash
my solution has two things: (1) add beginUpdates / endUpdates (2) add a bool variable to check whether view was already loaded or not
more explanation: if beginUpdates triggers a view reload cycle then viewcontroller will note that datasource already increased, so no insertRowsAtIndexPaths needs, if beginUpdates not triggers view reload cycle then neigter numberOfRowsInSection will be called so insertRowsAtIndexPaths can be called
func controller(controller: NSFetchedResultsController!, didChangeObject anObject: AnyObject!, atIndexPath indexPath: NSIndexPath!, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath!) {
if controller == frc {
switch(type) {
case .Insert:
isLayoutReloaded = false
self.tableView.beginUpdates() //<- !!!
if !isLayoutReloaded { //<- !!!
self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
}
self.tableView.endUpdates() //<- !!!
}
}
}
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
isLayoutReloaded = true //<- !!!
let numberOfRowsInSection = ((frc!.sections as NSArray)[0] as NSFetchedResultsSectionInfo).numberOfObjects
return numberOfRowsInSection
}
Related
I am playing with a table as below (I've seen multiple threads on this topic but couldn't answer my question):
func numberOfSections(in _: UITableView) -> Int {
3
}
func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 3
} else if section == 1 {
return 4
} else {
return 2
}
}
Then after clicking on a cell I want a new cell inserted into the same section at row index 0. I wrote the below:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.insertRows(at: [IndexPath(row: 0, section: indexPath.section)], with: .left)
}
I get this error:
Exception NSException * "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 (3), 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 assume I should somehow update the data source, but since in my case I return const values for rows in sections is there a way to update the the number of rows in section? (the numberOfRows in section only returns immutable value). Thank you
in my case I return const values
There you go! If you are going to modify the number of rows you need variables
For example
var sections = [3,4,2]
func numberOfSections(in _: UITableView) -> Int {
return sections.count
}
func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section]
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
sections[indexPath.section] += 1
tableView.insertRows(at: [IndexPath(row: 0, section: indexPath.section)], with: .left)
}
I have a table view with a certain number of rows. With a button on the same ViewController, I want to pop out one of the tableView rows. However, I am unable to do so. Note that I am not using editing style of table view but using a button on the same ViewController to delete a row from the tableView.
func postAction() {
postTable.deleteRows(at: [IndexPath(row: 0, section: 0)] , with: .fade)
}
However this results in crash. I am not sure why is this happening and how I should correct this. I intend to delete the first row from the only section here in the tableView (postTable)
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 (3), 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).'
My code:
postTable.delegate = self
postTable.dataSource = self
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = JobPostCellView(style: UITableViewCellStyle.default , reuseIdentifier: "PostCell")
cell.delegate = self
cell.name = arr[indexPath.row]
return cell
}
try this
func postAction() {
let indexPath = IndexPath(row: 0, section: 0)
yourmodel.remove(at: indexPath.row)//update your model also here
postTable.deleteRows(at: [indexPath] , with: .fade)
}
this may be happenig because you tableview row is not matching with the returning rows from number of rows in section method of your data source
for example
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
if you are returning 10 in your numberOfRowsInSection then there will be 10 rows in table
now you are deleting 1 row from it so the rows will be 9 but your numberOfRowsInSection method still returning 10 so this will create inconsistency so you have to update your count in numberOfRowsInSection section to return 9
and if you are using dynamic array than you have to delete it from your array also like in answer
I have an array:
var users = [Users]()
And in editActionsForRowAt I do following:
self.viewModel.users.remove(at: indexPath.row)
self.usersTableView.deleteRows(at: [indexPath], with: .automatic)
and it crashes on deleteRows with the next error:
attempt to delete row 0 from section 0 which only
contains 0 rows before the update
I tried to debug and found the next: when I remove a user from the array:
self.viewModel.users.remove(at: indexPath.row)
it removes somehow the row also! Like before this line
self.usersTableView.numberOfRows(inSection: 0)
gives me 1. After deletion from the array BUT before deleteRows it becomes equal to0`. I cannot understand the problem. It's so weird. Can someone help me to understand it?
UPDATE
numberOfRowsInSection:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.viewModel.users.count
}
// Variable and ViewDidLoad
var auxRow = 0
var auxSection = 0
override func viewDidLoad() {
super.viewDidLoad()
}
//Number Of Sections, only one section
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
auxSection += 1
print("times section: ", auxSection)
return 1
}
//Number Of Rows
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
auxRow += 1
print("times row: ", auxRow)
return 2
}
// TableView Configure the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let textCellIdentifier = "cellText"
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath)
let variable : String = indexPath.row.description
cell.textLabel?.text = variable
return cell
}
Output:
times section: 1
times row: 1
times section: 2
times row: 2
times section: 3
times row: 3
times section: 4
times row: 4
The method numberOfRowsInSection is being called 4 times. Why is that happening?
Apple makes no guarantees how often UIKit may call one of your delegate methods. They own the framework. We can expect them to cache that value but nothing requires them to do that.
You can set a breakpoint inside your numberOfRowsInSection method to see what it is being used for internally. There is no reason why it shouldn't be called multiple times, as it is called any time the tableview internally needs to know how many rows it has. It is called 4 times because Apple's tableview code needs to know, at 4 different times, how many rows are in your one section.
I have a UITableView and I have one of the required methods for its execution:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println("section is \(section)")
println(self.items.count) // self.items.count = 3
return self.items.count
}
In my log I see the method being run 3 times:
section is 0
3
section is 0
3
section is 0
3
EDIT:
This is the snippet of my section:
func numberOfSectionsInTableView(tableView:UITableView!)->Int
{
return 1
}
Picture of my thread stack: http://i.imgur.com/90dakCu.png
In the UITableView there are many situations, where different delegate-methods will get called multiple times due to something like auto-refreshing of the tableview.
Check this answer for more informations.