Я использую NSFetchedResultsController стандартным способом для обновления UITableView всякий раз, когда что-то изменяется в связанных объектах базовых данных. Я делаю так же, как описано в документации Apple .
Проблема у меня возникает, когда я делаю массовую вставку новых сущностей с основными данными. Это приводит к тому, что делегат NSFetchedResultsController выделяет (и вставляет) новую ячейку для каждой сущности, но делает это без повторного использования UITableViewCells (т.е. dequeueReusableCellWithIdentifier:
всегда возвращает ноль). Это означает выделение потенциально сотен UITableViewCells, что может привести к проблемам с памятью. Кто-нибудь знает об исправлении или обходном пути? Спасибо.
Редактировать 1:
В моем подклассе UITableViewController у меня есть стандартные методы NSFetchedResultsControllerDelegate. Я считаю, что это идентично примеру от Apple.
-(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
// Reloading the section inserts a new row and ensures that titles are updated appropriately.
[tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationTop];
break;
}
}
-(void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationBottom];
break;
}
}
-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
Также в моем подклассе UITableViewController у меня есть следующее для извлечения ячейки для заданного indexPath:
-(void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Waypoint *waypoint = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [waypoint comment];
}
-(UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"WaypointCell"; // matches identifier in XIB
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSLog(@"new cell");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
NSLog(@"recycled cell");
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
В функции tableView:cellForRowAtIndexPath:
я добавил операторы NSLog для отображения происходящего.
Вот что происходит. Вышеупомянутый UITableViewController помещается в стек навигации. Асинхронный запрос отправляется и извлекает кучу данных, а также создает или изменяет данные, связанные с этим fetchController. Как только [self.tableView endUpdates]
вызывается, система начинает создавать и вставлять UITableViewCells в UITableView. В консоли отладчика вывод «новая ячейка» печатается несколько раз (можно пронумеровать в сотнях), что, я полагаю, одно для каждой новой созданной сущности. Только после загрузки таблицы (если она не вылетала из-за проблем с памятью) и начала прокрутки, я вижу вывод «переработанной ячейки» в консоли.