代码之家  ›  专栏  ›  技术社区  ›  chris

NSFetchedResultsController委托分配了太多UITableViewCells

  •  1
  • chris  · 技术社区  · 15 年前

    in the Apple documentation .

    我遇到的问题是,当我大量插入新的核心数据实体时。这会导致NSFetchedResultsController委托为每个实体分配(并插入)一个新的单元格,但这样做时不会回收UITableViewCells(即。, dequeueReusableCellWithIdentifier: 总是返回null)。这意味着可能要分配100个UITableViewCells,这可能会导致内存问题。有人知道修复或解决方法吗?谢谢。

    在UITableViewController子类中,我有标准的NSFetchedResultsControllerDelegate方法。我相信这和苹果的例子是一样的。

    -(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:

    [self.tableView endUpdates] 调用时,系统开始创建UITableViewCells并将其插入UITableView。在调试器控制台中,输出“new cell”被打印多次(可以是100的数字),我相信每创建一个新实体就打印一次。只有在加载tableview(如果它没有因为内存问题而崩溃)并开始滚动之后,我才能在控制台中看到“recycled cell”输出。

    2 回复  |  直到 15 年前
        1
  •  1
  •   Florin    15 年前

    您确定要使用完全相同的标识符来创建和取消单元格排队吗(相同的标识符 dequeueReusableCellWithIdentifier: initWithStyle:reuseIdentifier: )

        2
  •  1
  •   chris    15 年前

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

    我的解决办法是引入 massUpdate 控制NSFetchedResultsController是否应如上所述插入新表行,或是否应执行简单操作的布尔值 [tableView reloadData]

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