NSFetchedResultsController委托分配太多UITableViewCells

时间:2010-08-16 10:59:59

标签: iphone objective-c core-data nsfetchedresultscontroller

我正在使用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之后(如果由于内存问题它没有崩溃)并且我开始滚动,我会在控制台中看到“回收单元”输出。

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

我的解决方案是引入一个massUpdate布尔值来控制NSFetchedResultsController是否应该如上所述插入新的表行,或者是否应该执行简单的[tableView reloadData]。我根据我计划插入的行数来设置它。有关实施的详细信息,请访问以下论坛帖子:

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