Removing the last Cell in UICollectionView makes a Crash - ios

Hi I'm working with a Custom UICollectionView (https://github.com/SureCase/WaterfallCollectionView) where everything works fine. Now I'm setting up delete items from the UICollectionView, and I can delete them fine. The problem comes when I'm trying to delete the last item of the section.
It gives the following error.
*** Assertion failure in -[UICollectionViewData layoutAttributesForSupplementaryElementOfKind:atIndexPath:], /SourceCache/UIKit/UIKit-2935.137/UICollectionViewData.m:787
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no UICollectionViewLayoutAttributes instance for -layoutAttributesForSupplementaryElementOfKind: UICollectionElementKindSectionHeader at path <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}'
The Code I'm using to delete items is the following:
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0){
NSLog(#"Erasing Objects!");
//First I remove Items from DataSource, and after from Collection View
[self deleteItemsFromDataSourceAtIndexPaths:selectedIndexes];
[self.cv deleteItemsAtIndexPaths:selectedIndexes];
[selectedIObjectsIndexes removeAllObjects];
[selectedIndexes removeAllObjects];
EditUICollection=NO;
EasyMediaGreenView.hidden = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.7 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self.cv reloadData];
});
}else{
NSLog(#"Not delete");
}
}
So first I'm removing items from DataSource and then from de Collection View. Here the Code for removing from Data Source.
-(void)deleteItemsFromDataSourceAtIndexPaths:(NSArray *)itemPaths
{
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for (NSIndexPath *itemPath in itemPaths) {
[indexSet addIndex:itemPath.row];
}
[idObject removeObjectsAtIndexes:indexSet];
[typeObject removeObjectsAtIndexes:indexSet];
[urlObject removeObjectsAtIndexes:indexSet];
[textObject removeObjectsAtIndexes:indexSet];
}
Why is this happening when I try to remove last object, when all other objects are removed correctly? I would like to understand this part, & any idea how to fix this? Thanks to all.

I Found a solution!
I was always returning 1 for section, so even with no items the CollectionView was being constructed, and asking to build a Header, like this:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSString *)kind
atIndexPath:(NSIndexPath *)indexPath; {
So I counted the items in my data array, and if the array is empty, there shouldn't be a section.
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
if(idObject.count>0){ return 1; }
else{ return 0; }
}
So where I'm deleting the items from my data array, I can check if the array is empty, if is not empty I'll delete items, if it is, I'll delete the entire section.
NSLog(#"Erasing Objects!");
[self deleteItemsFromDataSourceAtIndexPaths:selectedIndexes];
if(idShadeInside.count > 0){
[self.cv deleteItemsAtIndexPaths:selectedIndexes];
}
else{
//Creating an IndexSet with the Section to Erase
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];[indexSet addIndex:0];
[self.cv deleteSections:indexSet];
}
So problem fixed!

i have done this features, here i provides you a simple code to delete cell from Collection View.
Just pass you index in integer here.
-(void)remove:(int)i {
#try {
[self.collection performBatchUpdates:^{
[self.arrayThumbImg removeObjectAtIndex:i];
NSIndexPath *indexPath =[NSIndexPath indexPathForRow:i inSection:0];
[self.collection deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
} completion:^(BOOL finished) {
}];
}
#catch (NSException *exception) {
NSLog(#"Error: %#",exception);
}
#finally {
}
}

Related

NSInternalInconsistencyException while deleting cell from collectionView

I want to delete a cell from a UICollectionView. While deleting cell I get
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (5) must be equal to the number of items contained in that section before the update (5), plus or minus the number of items inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).' Error.
Here is my code:
[self.imgArray removeObjectAtIndex:indexForDelete];
[self.collectionView performBatchUpdates:^{
NSIndexPath *indexPath =[NSIndexPath indexPathForItem:indexForDelete inSection:0];
[self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
} completion:^(BOOL finished) {
}];
I am appending one dummy cell when my array count is not 5
Here is code for numberOfItems in numberOfItemsInSection
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if(self.imgArray.count == 5)
{
return self.imgArray.count ;
}
else
{
return self.imgArray.count + 1;
}
}
I found many solution on Google and Stackoverflow but nothing found help full for me.
performBatchUpdates mainly used to perform actions for multiple cells. i.e. delete, insert, move.
Try this,
[self.collectionObj performBatchUpdates:^{
[self.imgArray removeObjectAtIndex:indexForDelete];
NSIndexPath *indexPath =[NSIndexPath indexPathForItem:indexForDelete inSection:0];
[self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
[self.collectionView reloadData];
} completion:^(BOOL finished) {
}];
You can also try directly for 1 cell delete without using performBatchUpdates
[self.imgArray removeObjectAtIndex:indexForDelete];
NSIndexPath *indexPath =[NSIndexPath indexPathForItem:indexForDelete inSection:0];
[self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
[self.collectionView reloadData];
Hope, this will help you.
Thanks
I think you may need to separate the update into two stages to avoid the NSInternalInconsistencyException.
#property (assign, nonatomic) BOOL isMyCollectionViewUpdating;
//...
[self.imgArray removeObjectAtIndex:indexForDelete];
[self.collectionView performBatchUpdates:^{
self.isMyCollectionViewUpdating = YES;
NSIndexPath *indexPath =[NSIndexPath indexPathForItem:indexForDelete inSection:0];
[self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
} completion:^(BOOL finished) {
self.isMyCollectionViewUpdating = NO;
[self.collectionView reloadData];
}];
and for the collection view numberOfItemInSection
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (self.isMyCollectionViewUpdating)
{
return self.imgArray.count;
} else {
if(self.imgArray.count == 5)
{
return self.imgArray.count ;
}
else
{
return self.imgArray.count + 1;
}
}
}

UICollectionView cellForItemAtIndexPath is called but data source is empty

I have a custom tab on top of view which a user can switch two view back and forth. Both view contains UICollectionView dynamically filled with data from a server. In my understanding, if numberOfItemInSection return 0 when [collectionView reloadData] is called, cellForItemAtIndexPath won't be called. In other word, if cellForItemAtIndexPath is being called, it means there is some data in source. Below is some code I used when switch to one view to other view.
- (void)refresh
{
[self.collectionView setContentOffset:CGPointZero];
[self.data removeAllObjects];
[self.refreshControl beginRefreshing];
if (self.collectionView.contentOffset.y == 0) {
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
self.collectionView.contentOffset = CGPointMake(0, -MPViewHeight(self.refreshControl));
} completion:^(BOOL finished){
}];
}
[self.collectionView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
[self requestToServerAtIndex:0];
}
- (void) requestToServerAtIndex:(NSInteger)index
{
#weakify(self)
[[self.serverHelper getData:index requestCount:20] subscribeNext:^(id JSON) {
#strongify(self)
NSArray *data = [ParserForJSON parse:JSON];
if(data.count != 20) {
self.moreData = NO;
}
[self.data addObjectsFromArray:data];
[self.collectionView reloadData];
[self.refreshControl endRefreshing];
} error:^(NSError *error) {
}];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.data.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomData *data = [self.data objectAtIndex:indexPath.row];
CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
///.... some cell configuration
return cell;
}
However, I got random crash on cellForItemAtIndexPath when it tried to access data source which was happened to be empty. Surprisingly, the data source was not empty when I checked on console at that point. So my wild guess is there was some timing issue. I would like to get some in depth explanation on this ambiguous behavior.
When you call refresh method, you remove all data objects, so when your cellForItemAtIndexPath was called, there's no data in data source. That's why when call id object = [data objectAtIndex:indexPath.row] return nil. So make sure after requestToServerAtIndex make the new datas realy then remove the old objects and update the UI.
EDIT:
Try to remove [self.collectionView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; to test, this method should call cellForItemAtIndexPath

UICollectionView - Remove All Items Or Update to Refresh it

I am working on an UICollectionView based app, and I load it by -
NSUInteger newNumCells = [self.imageArray count];
NSIndexPath* newIndexPath;
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
[indexPaths removeAllObjects];
for (int i = 0; i < newNumCells; ++i) {
newIndexPath = [NSIndexPath indexPathForItem:i inSection:0];
[indexPaths addObject:newIndexPath];
}
self.indexPaths = indexPaths;
[self.collectionView insertItemsAtIndexPaths:indexPaths];
[self.collectionView reloadData];
It's working well.
Then I have another search function at same page, so when I get new search result from server, the self.imageArray content changed, I want to refresh current UICollectionView, for example, remove all items, and insert new items from current self.imageArray, but when I do delete items, always crash -
[self.collectionView performBatchUpdates:^{
//self.indexPaths = [self.collectionView indexPathsForVisibleItems];
//[self.imageArray removeAllObjects];
self.indexPaths = [self.collectionView indexPathsForVisibleItems];
[self.imageArray removeAllObjects];
[self.collectionView deleteItemsAtIndexPaths:self.indexPaths];
[self.collectionView.collectionViewLayout invalidateLayout];
//[self.collectionView reloadData];
//[self.collectionView deleteItemsAtIndexPaths:[self.collectionView indexPathsForVisibleItems]];
} completion:nil];
Crash info -
Assertion failure in -[UICollectionViewData validateLayoutInRect:], /SourceCache/UIKit_Sim/UIKit-2903.2/UICollectionViewData.m:341
2014-03-07 11:47:48.450 pixcell8[9089:a0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UICollectionView recieved layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0xb4a8430> {length = 2, path = 0 - 0}'
So I want to ask how to do refresh the UICollectionView with new data? Thanks.
Update : this bug is because I have used a custom layout, and it had some wrong logics, and now it's fixed.
loading a collection view is very similar to a table view. Use the delegate and dataSource protocols for handling most of this.
for you case something like
self.collectionView.dataSource = self;
then in dataSource methods
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return self.imageArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
//Set up and return your cell
}
When you want to change content you can replace or update contents of imageArray and reloadData.
New content from API comes in
[self.imageArray removeAllObjects];
[self.imageArray addObjectsFromArray:apiResponseArray];
[self.collectionView reloadData];
There are other approaches that maybe a bit more efficient but this should get you started. You can use the other methods for insert and batch as needed once the basic set up is done correctly.

Why am I getting an assert Error When trying to Delete a section in a tableview ios

I have a tableView with some sections, which all have a footer, and then I have a tableViewFooter on the Tableview itself.
If I scroll down to the bottom of my tableview and delete the last item(therefore deleting the section altogether) in any sections above the last section (second last and up) it gives me this error
2014-02-21 13:19:55.066 xxxx[5436:60b] *** Assertion failure in -[UIViewAnimation initWithView:indexPath:endRect:endAlpha:startFraction:endFraction:curve:animateFromCurrentPosition:shouldDeleteAfterAnimation:editing:], /SourceCache/UIKit/UIKit-2903.23/UITableViewSupport.m:2661
Uncaught exception: Cell animation stop fraction must be greater than start fraction
at endUpdates
this is my code
[self.tableView beginUpdates];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
if(indexPath != nil){
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
NSMutableDictionary *dic =[sec.items objectAtIndex:indexPath.row];
Product* product = [dic valueForKey:PRODUCT];
//removing the item in the section
[sec.items removeObject:dic];
//deleting item from products
NSMutableArray *temp = [NSMutableArray array];
for (Product *p in self.dataCon.listPersister.products) {
if ([p.product.objId isEqualToString: product.product.objId]) {
[temp addObject:p];
}
}
for (Product *p in temp) {
[self.dataCon.listPersister.products removeObject:p];
}
//if it was the last object in section, delete the section else just delete the single row
if(sec.items.count == 0)
{
[self.sections removeObject:sec];
[self.footers removeObjectAtIndex:indexPath.section];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
} else
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
USFooterView *footer = [self.footers objectAtIndex:indexPath.section];
footer.totalLabel.text = [self.dataCon.listPersister getTotalForShopId:sec.title];
self.footerView.totalLabel.text = [self.dataCon.listPersister getTotalForAllProducts];
}
}
[self.tableView endUpdates];
I had the same code earlier, just without my tableView and table sections having footers, where it worked, so I think they might be the problem, but I'm not entirely sure that's the reason it's acting up.
I have seen this post
UITableView tableFooterView may cause crash?
And the post that it links to, but that didn't help me.
Any help is appreciated :)
In the else statement you delete row from table view:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
But not from data source. Delete row from array which you use as data source and it should works.
I found a "fix", but I'm avoiding the use of sectionFooter, because that seems to be bugged.
I created an extra cell at the end of each section, with the same setup I had for my footer View before, and made that last cell not editable with
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
if (sec.items.count != indexPath.row) {
return YES;
} else
return NO;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [sec.items count] +1 ;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"normalcell";
static NSString *CellIdentifier1 = #"footercell";
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
if (indexPath.row != sec.items.count) {
//use normal type of cell
return cell;
} else{
//use footer type of cell
return cell;
}
}
So the last cell Imitates a "footer", but it's not stuck to the bottom of the frame, but I'll have to live with that. It's better than crashes.
Try using UITableViewRowAnimationLeft or UITableViewRowAnimationRight as the delete row animation(deleteRowsAtIndexPaths:withRowAnimation:).
It crashed for me when using UITableViewRowAnimationAutomatic, but not with the other two. I have not tried all of them but it seems to be a bug with the animation code for some of the options.

Rows not being inserted into UITable

I have an app with a table view that expands/collapses sections, following the example in Apple's Table View Animations & Gestures sample app. I am running into problems when an item is added to a closed section: after that, the section no longer opens, and I get an exception when I try to open and then close it.
I've traced this to some strange behaviour in the open/close methods:
-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionOpened:(NSInteger)section {
if (![[sectionHeaderArray objectAtIndex:section] isOpen]) {
[[sectionHeaderArray objectAtIndex:section] setIsOpen:YES];
NSLog(#"self.tableView: %#", self.tableView);
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSInteger countOfRowsToInsert = [sectionInfo numberOfObjects];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
// Apply the updates.
[self.tableView beginUpdates];
NSLog(#"Count of rows to insert: %d", [indexPathsToInsert count]);
NSLog(#"Rows before insert: %d", [self.tableView numberOfRowsInSection:section]);
[self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationTop];
NSLog(#"Rows after insert: %d", [self.tableView numberOfRowsInSection:section]);
[self.tableView endUpdates];
}
}
-(void)sectionHeaderView:(SectionHeaderView*)sectionHeaderView sectionClosed:(NSInteger)section {
if ([[sectionHeaderArray objectAtIndex:section] isOpen]) {
[[sectionHeaderArray objectAtIndex:section] setIsOpen:NO];
NSInteger countOfRowsToDelete = [self.tableView numberOfRowsInSection:section];
if (countOfRowsToDelete > 0) {
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.tableView beginUpdates];
NSLog(#"Count of rows to delete: %d", [indexPathsToDelete count]);
NSLog(#"Rows before delete: %d", [self.tableView numberOfRowsInSection:section]);
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
NSLog(#"Rows after delete: %d", [self.tableView numberOfRowsInSection:section]);
}
[self.tableView endUpdates];
}
}
The log messages show that, on open (insert rows), >0 rows are being inserted, and yet the row count for that section stays 0:
2012-03-31 13:36:17.454 QuickList7[5523:fb03] Count of rows to insert: 3
2012-03-31 13:36:17.454 QuickList7[5523:fb03] Rows before insert: 0
2012-03-31 13:36:17.454 QuickList7[5523:fb03] Rows after insert: 0
This sets up an inconsistent state between the table and data source, and then when I try to "collapse" the section, I get the following exception:
2012-03-31 13:48:35.783 QuickList7[5523:fb03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid table view update. The application has requested an update to the table view that is inconsistent with the state provided by the data source.'
How can I insert 3 rows, and still end up with 0 rows?
Thanks,
Sasha
I found the problem! It was actually in the fetchedResultsController's change handler. It was responding to changes to closed sections, which left the table in a bad state, and out of sync with the data source. So I added a check for each update to only insert/delete/update rows if the containing section is open.
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tv = self.tView;
switch(type) {
case NSFetchedResultsChangeInsert:
if ([[sectionHeaderArray objectAtIndex:newIndexPath.section] isOpen]) {
[tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
break;
case NSFetchedResultsChangeDelete:
if ([[sectionHeaderArray objectAtIndex:indexPath.section] isOpen]) {
[tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
break;
case NSFetchedResultsChangeUpdate:
if ([[sectionHeaderArray objectAtIndex:indexPath.section] isOpen]) {
[self configureCell:[tv cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
}
break;
case NSFetchedResultsChangeMove:
if ([[sectionHeaderArray objectAtIndex:indexPath.section] isOpen]) {
[tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
if ([[sectionHeaderArray objectAtIndex:newIndexPath.section] isOpen]) {
[tv insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
}
break;
}
}
In my app I've implemented a similar behavior in a very different way because I was running into this type of problem a lot.
I have a table with MenuNameCells, MenuItemCells and a static cell at the bottom. Only one menu is expanded at a time, and tapping a MenuNameCell expands or collapses that menu. Since I keep the MenuNameCell in its own section and the MenuItemCells in another, I only have to insert/delete entire sections when I reload the table.
Here's my table's data source:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// number of menus, plus 1 if a menu is open, plus 1 static cell
return [self.restaurant.menus count]+(self.menu != nil ? 1 : 0)+1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// if this section is our selected menu, return number of items, otherwise return 1
int numberOfRowsInSection = ([self indexPathIsInMenuItemSection:section] ? [[self.menu items] count] : 1);
return numberOfRowsInSection;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == [tableView numberOfSections]-1) {
// ... set up and return static cell
}
if ([self indexPathIsInMenuItemSection:indexPath.section]) {
// ... set up and return menu item cell
} else {
// ... set up and return menu name cell
}
}
and my table's delegate:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// return if it's a static cell
if (indexPath.section==[tableView numberOfSections]-1)
return;
// if it's a menu name cell, close open menu and maybe expand this menu
if (![self indexPathIsInMenuItemSection:indexPath.section]) {
BOOL reset = self.menu == m;
if (reset) [self reloadTableView:self.tableView withMenu:nil animated:YES autoscroll:NO];
else [self reloadTableView:self.tableView withMenu:m animated:YES autoscroll:YES];
}
}
There were a couple of helpers mentioned in there:
- (BOOL)indexPathIsInMenuItemSection:(NSInteger)section
{
// returns YES if section refers to our MenuItemCells
int indexOfMenu = [self.restaurant getIndexOfMenu:self.menu];
return indexOfMenu != -1 && section == indexOfMenu+1;
}
- (void)reloadTableView:(UITableView *)tableView withMenu:(Menu *)menu animated:(BOOL)animated autoscroll:(BOOL)autoscroll
{
int oldIndex = [self.restaurant getIndexOfMenu:self.menu];
int newIndex = [self.restaurant getIndexOfMenu:menu];
[tableView beginUpdates];
if (oldIndex != -1) {
// index of [section for items] is oldIndex+1
[tableView deleteSections:[NSIndexSet indexSetWithIndex:oldIndex+1] withRowAnimation:UITableViewRowAnimationTop];
}
if (newIndex != -1) {
// index for [section for items] is newIndex+1
[tableView insertSections:[NSIndexSet indexSetWithIndex:newIndex+1] withRowAnimation:UITableViewRowAnimationTop];
[self setMenu:menu];
} else {
// no new menu
[self setMenu:nil];
}
[tableView endUpdates];
if (autoscroll) [self autoscroll];
}
- (void)autoscroll
{
if (self.menu != nil) {
int section = [self.restaurant getIndexOfMenu:self.menu];
if (section != -1) {
NSUInteger indexes[] = {section,0};
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:indexes length:2];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
}
Since my data is loaded asynchronously elsewhere, I have this controller set up to receive an NSNotification, but it should work just as well to call this on viewDidAppear:
[self reloadTableView:self.tableView withMenu:self.menu animated:YES autoscroll:YES];
I hope this helps! Let me know if I can clarify any of it.

Resources