Inserting cell to top of uitableview causes problems - ios

This is driving me nuts, I have sections in my UITableView, but this insertion works when I don't have sections.
Basically I'm doing:
[self.tableView insertRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationRight];
I'm getting this error:
The number of sections contained in the table view after the update (5) 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 thought it would just work, but this doesn't make sense. What can you guys make of this?

You are returning different values from your numberOfSectionsInTableView: method before and after you send the insertRowsAtIndexPaths:withRowAnimation: method.
If you are creating an entirely new section in the table view, you must insert it by sending insertSections:withRowAnimation: message to the table view.

Whenever you make a insertRowsAtIndexPaths:withRowAnimation call, you also need to modify the data source that backs the table with a similar addition. This ensures that tableView:numberOfRowsInSection: returns n before the addition and n+1 after the addition. Anything besides a consistent result with throw the error you described.

Related

iOS UITableView - crash when inserting new section with error message which may indicate that I should call moveSection:toSection: method

I reload, insert and delete table view's rows and sections in a single begin/end update block. I do not call moveSection:toSection: nor moveRowAtIndexPath:toIndexPath: method.
I am aware that deletion and reloading of existing cells are being executed first, regardless of the order of method calls in update block. I do not insert rows for the new section that is inserted. Also, I am updating data source before table view update block.
Deletion and reloading work just fine for me, but I have a problem with inserting new sections. I got error messages of type:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 5. 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 (3), plus or minus the number of rows inserted or deleted from that section (0 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 is interesting that I do not delete or reload any table view's rows and sections in the corresponding table view update block. Also, there is 1 row in all sections that come before section 5. New section was inserted at index 0. So it seems to me that I might be missing moveSection:toSection: method call..?
I couldn't find more complex examples of simultaneous inserting, deleting and reloading rows and sections in a single update block on Internet, so I would really appreciate any suggestions and links to the examples that could guide me how to handle more complex table view updates.

Infinite UITableView Scroll with NSFetchedResultsController

I'm trying to use this method to implement an infinitely scrolling UITableView
The core logic of the solution is:
To increase the tableview content by a factor of 3, so that we make the 3 copies of the content laid one after another vertically.
Whenever the top end of the scroll is reached, move the the scroll offset back to start of the 2nd copy
When the bottom end of the scroll is reached, we move the scroll offset back to the start of the 2nd copy minus the height of the tableview, so that we end up showing the same content as we are now.
This means that a single cell insert or delete actually results in three inserts or deletes. Because my table's datasource is populated by an NSFetchedResultsController it causes an Assertion Failure.
The number of rows contained in an existing section after the update (12) must be equal to the number of rows contained in that section before the update (15), 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).
Is there some way to stop the program from crashing in these cases? I'd really appreciate any help/pointers. Thanks.
This can be kind of tricky in iOS especially when you're first starting out. The key is to update the datasource that is backing your UITableView before you inform the tableview of changes.
For instance, if you have an NSArray backing your tableview, then you will want to remove or add items to it, prior to calling reloadSection: on the tableview.
Although it is the least optimized solution, while your testing feel free to simply call reloadData which will ignore what the tableview has cached and force it to recalculate based on whatever is backing the tableview.
You can use NSFetchedResultsControllerDelegate method controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:. To insert\delete 3 objects.
To keep it simple you could return 3 for number of sections in your table view (this will handle getting 3 copies of objects). And then in your NSFetchedResultsControllerDelegate update objects in all sections of your UITableView (insert, delete or move). You should use row number from the NSFetchedResultsControllerDelegate and apply all changes 3 times each for different section. Remember to keep it consistent with UITableView data source method tableView:numberOfRowsInSection:.

UITableview reloadRowsAtIndexPaths crash when table data gets updated

I have a table view with each rows having image and some text. The images are loaded asyc. As soon as image is fetched from server, the delegate methods gets called. The delegate method contains the index path which initiated the image fetching, so that I can reload only those cells. I have extra check to make sure that once the image is fetched, the data source contains enough data so that index path doesn't go out of bounds. Despite setting this condition the app crashes.
There is a chance that my table data gets updated before the image is fetched. I know this is cause of the issue, but I am not sure why this is making a crash despite adding a check before
reloadRowsAtIndexPaths?
The error is:
Fatal Exception NSInternalInconsistencyException Invalid update: invalid number of rows in section 2. The number of rows contained in an existing section after the update (4) 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 (1 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
Can some one share any inputs on this?
Code snippet that reloads the table
// this method will be called on main thread
- (void)loadImageAtIndexPath:(NSIndexPath *)inIndexPath {
if(inIndexPath.row < dataSource.count) {
[self.listView reloadRowsAtIndexPaths:[NSArray arrayWithObject:inIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
}

Partially-rendered UITableView header

I am populating a UITableView from an array - lets call it sections. The numberOfSectionsInTableView returns sections.count, except for a special case - if sections.count is 0, I return 1 (1 is the minimum number of sections that should ever be returned by numberOfSectionsInTableView). I return nil as the section header in this case, so the UITableView looks empty.
When a new item is added to my dataSource, I manually insert a new row. I also check if a new section is required, and if so I add it to sections and insert the new section. But here is where my 'special case' causes problems.
When adding the first item, to the first section, I don't want to add a new section (because there is already one section minimum at all times). So, I just insert the row.
The row animation insertion seems correct, but I get a strange half-loaded header:
All I really need to do is make the UITableView reload the header when the first row is inserted. But I don't want to lose the insertion animations by simply reloading the tableview or the section.
Any ideas?
I think that you are looking for -reloadSections:withRowAnimation:.
After you add or remove the special case of section 0, you can call:
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
Hope that helps.

UITableView's reloadRowsAtIndexPaths: seems to break insertRowsAtIndexPaths:

I have a UITableView into which the user can insert new rows. When this happens, I want to reload all of the old rows in the table. One solution would be to just call reloadData as soon as the insertion takes place, which totally works, but this means I don't get the insertion animation.
So when the user hits the "add row" button, I call reloadRowsAtIndexPaths: with every index path except the one just inserted. Then I call insertRowsAtIndexPaths: with only the newly inserted row. Reasonable, right?
This causes the app to crash with the following explanation:
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 (0), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
This happens, as you can see in this example, even when reloadRowsAtIndexPaths is passed an empty array of index paths.
Ah! I need to wrap the two calls with beginUpdates and endUpdates. Fair enough. But now the animation is completely broken.
I'm performing the reload with a UITableViewRowAnimationFade and the insertion with a UITableViewRowAnimationAutomatic. But during the animation, the heights of every row changes, creating this weird flickery effect that looks just terrible. What's the correct way to animate these changes?
Edit:
From the docs for reloadRowsAtIndexPaths:withRowAnimation::
Reloading a row causes the table view to ask its data source for a new cell for that row. The table animates that new cell in as it animates the old row out. Call this method if you want to alert the user that the value of a cell is changing. If, however, notifying the user is not important—that is, you just want to change the value that a cell is displaying—you can get the cell for a particular row and set its new value.
I think that, in my application, manually updating each cell is the right way to go. However, I am still perturbed by this bizarre animation bug, and would like to know what the cause of it is / what I would do if I did "want to alert the user that the value of the cell is changing."
A common reason for getting that error is, as the docs say, the datasource is asked for a cell. It might be less clear that it is asked twice...once to provide the initial data, again to provide the final data. That implies that the tableView:numberOfRowsInSection: method must return the old values before beginUpdates and the new values after endUpdates (or if you're using a shortcut method, before and after the call). Don't forget about numberOfSectionsInTableView either if it is relevant.
Example:
numberOfRows... return [array count];
// Incorrect
[array addObject:object];
[tableView beginUpdates];
[tableView insertRow..];
[tableView endUpdates];
// Correct
[tableView beginUpdates];
[array addObject:object];
[tableView insertRow..];
[tableView endUpdates];
For your specific case, I would recommend doing the insertion, then calling reloadData on the whole tableview so long as that doesn't mess up your animation or anything else.
You don't need to have any operations with exactly cells. All what you need - is change your datasource array, then call reload data/row/section, and you'll get changed data in your table view, with added rows.

Resources