2010-08-16 64 views
1

我正在使用NSFetchedResultsController标准的方式来更新一个UITableView只要有关的核心数据实体发生变化。我所做的和in the Apple documentation一样。NSFetchedResultsController委托分配太多的UITableViewCells

我遇到的问题是当我对新的核心数据实体进行批量插入时。这导致NSFetchedResultsController委托为每个实体分配(并插入)一个新的单元格,但是它没有循环使用UITableViewCells(即总是返回空值)。这意味着分配潜在的100个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中。在调试器控制台中,输出“新单元”被多次打印(可以在100年代编号),我相信这是每个​​创建的新实体的一个。只有在tableview被加载后(如果它没有因内存问题而崩溃)并且我开始滚动时,我是否可以在控制台中看到“回收单元”输出。

+0

我只注意到你一共有4个问题,他们都没有一个公认的答案。如果答案解决了您的问题,您应该通过点击绿色标志来接受答案。 :) – Florin 2010-08-16 14:09:34

+0

你需要显示你的代码。这不是正常的行为。代表本身不会创建单元格。您不正确地插入某处的单元格。 – TechZen 2010-08-17 00:48:01

+0

弗洛林:我会适当地重新访问和更新。感谢提高。 TechZen:我已经在原文中添加了一些代码。我希望能够对这个问题有所了解。最初我使用了一个自定义tableviewcell与.xib,但我简化了代码使用标准的UITableViewCell和行为是完全一样的。更正委托不创建单元格。这是来自委托的[tableView endUpdates]调用。谢谢。 – chris 2010-08-17 10:16:06

回答

1

我找到了一个我很满意的解决方案。问题本身不是NSFetchedResultsController,而是它可能从NSFetchedResultsController委托中调用[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationTop]数百次。

我的解决方案是引入一个massUpdate布尔值,用于控制NSFetchedResultsController是否应如上所述插入新的表格行,或者是否应该执行简单的[tableView reloadData]。我根据我打算插入的行数来设置它。实施细节可以在下面的论坛帖子中找到:

https://devforums.apple.com/message/181219#181219

+1

在处理新项目时,我在Apple的RootViewController.m模板文件中发现了以下评论,该文件位于NSFetchedResultsControllerDelegate方法下:“实施上述方法更新表视图以响应各个更改可能会对性能产生影响,如果发生大量更改如果这被证明是一个问题,你可以改为实现controllerDidChangeContent:它通知委托所有部分和对象的更改已经被处理。“看起来这是一个已知的问题。 – chris 2010-10-16 15:33:27

+0

你从哪里找到苹果的摘录?谢谢! – jpswain 2012-06-21 05:04:17

+0

我在XCode附带的项目模板中找到它。创建一个新项目,选择主 - 细节应用程序,并确保选中使用核心数据。您将在MasterViewController.m中找到该评论。 – chris 2012-06-27 07:39:03

1

您确定您使用完全相同的标识符来创建和出队单元吗? (相同标识符dequeueReusableCellWithIdentifier:initWithStyle:reuseIdentifier:

+0

我很确定这是正确的。我在不同的地方放置NSLog语句来监视行为,并且在正常的表浏览(向上和向下滚动)上一切正常。在表格加载时,我看到5或6个单元格的初始分配,当我上下滚动时,它们会被重用。这只是一个大规模的表更新(原来描述的问题),我看到100分配。 另外,在大量分配后,大多数会被释放。我认为这些是不可见的表格单元,因为滚动然后返回到预期的行为。 – chris 2010-08-16 14:59:21

相关问题