我正在使用NSFetchedResultsController以标准方式在相关核心数据实体中发生更改时更新UITableView。我的描述与in the Apple documentation所描述的相同。
我遇到的问题是当我批量插入新的核心数据实体时。这会导致NSFetchedResultsController委托为每个实体分配(并插入)一个新的单元格,但它会在不循环使用UITableViewCells的情况下执行此操作(即,dequeueReusableCellWithIdentifier:
始终返回null)。这意味着可能会分配100个UITableViewCell,这可能会导致内存问题。有没有人知道修复或解决方法?感谢。
编辑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]
后,系统开始创建UITableViewCell并将其插入UITableView。在调试器控制台中,输出“new cell”被多次打印(可以在100s中编号),我相信每个新实体创建一个。只有在加载了tableview之后(如果由于内存问题它没有崩溃)并且我开始滚动,我会在控制台中看到“回收单元”输出。
答案 0 :(得分:1)
您确定使用完全相同的标识符来创建和出列单元格吗? (dequeueReusableCellWithIdentifier:
和initWithStyle:reuseIdentifier:
的相同标识符)
答案 1 :(得分:1)
我找到了一个我很满意的解决方案。问题不在于NSFetchedResultsController本身,而是从NSFetchedResultsController委托中调用[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationTop]
可能数百次。
我的解决方案是引入一个massUpdate
布尔值来控制NSFetchedResultsController是否应该如上所述插入新的表行,或者是否应该执行简单的[tableView reloadData]
。我根据我计划插入的行数来设置它。有关实施的详细信息,请访问以下论坛帖子: