Ok, so I need to prevent the table from scrolling when new items are added over the current visible row. I use NSFetchedResultsController with a lot of objects (e.g. 10,000), and reloadData works pretty smoothly when I don't touch contentOffset.
However, when I try to manipulate the contentOffset to maintain the scroll position when inserting new records, it starts to freeze the user interface in about 300 ms, which is bad for me.
Can anyone suggest a better (faster) solution on how to save the table in one cell when adding new items at the top?
And this is the code that I am currently using to track the insertion and change of contentOffset. It does not support animation and cell size.
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { switch(type) { case NSFetchedResultsChangeInsert: [_insertions addObject:@(newIndexPath.row)]; break; } } - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { _insertions = @[].mutableCopy; } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { NSMutableArray *copy = _insertions.mutableCopy; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSSortDescriptor *lowestToHighest = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES]; [copy sortUsingDescriptors:[NSArray arrayWithObject:lowestToHighest]]; dispatch_sync(dispatch_get_main_queue(), ^{ for (NSNumber *i in copy) { [self p_delayedAddRowAtIndex:[i integerValue]]; } [self.tableView reloadData]; }); }); } - (CGFloat)p_firstRowHeight { return [self tableView:[self tableView] heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; } -(void)p_delayedAddRowAtIndex:(NSInteger)row { NSIndexPath *firstVisibleIndexPath = [[self.tableView indexPathsForVisibleRows] firstObject]; if (firstVisibleIndexPath.row >= row) { CGPoint offset = [[self tableView] contentOffset]; offset.y += [self firstRowHeight]; if ([self.tableView visibleCells].count > self.tableView.frame.size.height / [self firstRowHeight]) { [[self tableView] setContentOffset:offset]; } } }
ios objective-c uitableview core-data nsfetchedresultscontroller
kandreych
source share