2

The documentation says:

You should consider carefully whether you want to update the table view as each change is made. If a large number of modifications are made simultaneously—for example, if you are reading data from a background thread— /.../ you could just implement controllerDidChangeContent: (which is sent to the delegate when all pending changes have been processed) to reload the table view.

This is exactly what I'm doing: I'm processing incoming changes in a background thread with a different ManagedObjectContext, and merge the results into the main thread MOC with mergeChangesFromContextDidSaveNotification:. So far so good.

I chose to not implement controller:didChangeObject:... and would instead like to do the batched update that the document suggests.

Question/problem: the document doesn't elaborate how to actually implement the batched update? Should I just call [tableview reloadData] in controllerDidChangeContent: or is there a less intrusive way that saves me from a full reload?

One thought I have: I could take note of mergeChangesFrom... notification that contains the changed objects, figure out their indexpaths, and just call tableview:ReloadRowsAtIndexPaths: for them. But is there any authoritative info, recommendations or examples? Or just [tableview reloadData]?

(Aside: controller:didChangeObject:... started behaving really erratically when it received a set of batched updates, even though the same updating code [that I now put in background thread] was fine before when it was running on the main thread, but of course locking up the UI.)

4

3 回答 3

1

我相信这就是您正在寻找的:

而不是打电话

  • deleteSections
  • insertSections
  • reloadSections
  • deleteRowsAtIndexPaths
  • insertRowsAtIndexPaths
  • reloadRowsAtIndexPaths

随着更改的到来controller:didChangeObject:atIndexPath:forChangeType:newIndexPath,收集属性中的 indexPaths 和部分。然后在中执行批处理controllerDidChangeContent:

参考:http ://www.fruitstandsoftware.com/blog/2013/02/19/uitableview-and-nsfetchedresultscontroller-updates-done-right/

编辑

这是链接中提到的方法的一个稍微不同、更做作但也更紧凑的版本:

@property (nonatomic, strong) NSMutableArray *sectionChanges;
@property (nonatomic, strong) NSMutableArray *objectChanges;

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{

}

- (void)controller:(NSFetchedResultsController *)controller
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex
     forChangeType:(NSFetchedResultsChangeType)type
{
    NSMutableDictionary *sectionChange = [NSMutableDictionary new];

    switch(type)
    {
        case NSFetchedResultsChangeInsert:
        case NSFetchedResultsChangeDelete:
        case NSFetchedResultsChangeUpdate:
            sectionChange[@(type)] = @(sectionIndex);
            break;
    }

    [self.sectionChanges addObject:sectionChange];
}

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    NSMutableDictionary *objectChange = [NSMutableDictionary new];

    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            objectChange[@(type)] = newIndexPath;
            break;
        case NSFetchedResultsChangeDelete:
        case NSFetchedResultsChangeUpdate:
            objectChange[@(type)] = indexPath;
            break;
        case NSFetchedResultsChangeMove:
            objectChange[@(type)] = @[indexPath, newIndexPath];
            break;
    }

    [self.objectChanges addObject:objectChange];        
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    UITableView *tableView = self.tableView;

    NSUInteger totalChanges = self.sectionChanges.count + self.objectChanges.count;

    if (totalChanges > 0)
    {
        [tableView beginUpdates];

        if (self.sectionChanges.count > 0)
        {
            for (NSDictionary *change in self.sectionChanges)
            {
                [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {

                    NSFetchedResultsChangeType type = [key unsignedIntegerValue];

                    switch (type)
                    {
                        case NSFetchedResultsChangeInsert:
                            [tableView insertSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]] withRowAnimation:UITableViewRowAnimationAutomatic];
                            break;
                        case NSFetchedResultsChangeDelete:
                            [tableView deleteSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]] withRowAnimation:UITableViewRowAnimationAutomatic];
                            break;
                        case NSFetchedResultsChangeUpdate:
                            [tableView reloadSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]] withRowAnimation:UITableViewRowAnimationAutomatic];
                            break;
                    }
                }];
            }
        }
        else if (self.objectChanges > 0)
        {
            NSMutableArray *indexPathsForUpdatedObjects = [NSMutableArray new];

            for (NSDictionary *change in self.objectChanges)
            {
                [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {

                    NSFetchedResultsChangeType type = [key unsignedIntegerValue];
                    switch (type)
                    {
                        case NSFetchedResultsChangeInsert:
                            [tableView insertRowsAtIndexPaths:@[obj] withRowAnimation:UITableViewRowAnimationAutomatic];
                            break;
                        case NSFetchedResultsChangeDelete:
                            [tableView deleteRowsAtIndexPaths:@[obj] withRowAnimation:UITableViewRowAnimationAutomatic];
                            break;
                        case NSFetchedResultsChangeUpdate:
                            [indexPathsForUpdatedObjects addObject:obj];
                            //[tableView reloadRowsAtIndexPaths:@[obj] withRowAnimation:UITableViewRowAnimationAutomatic];
                            break;
                        case NSFetchedResultsChangeMove:
                            [tableView moveRowAtIndexPath:obj[0] toIndexPath:obj[1]];
                            break;
                    }
                }];
            }

            [tableView endUpdates];

            for (NSIndexPath *indexPath in indexPathsForUpdatedObjects)
                if ([tableView.indexPathsForVisibleRows containsObject:indexPath])
                    [self updateCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
        }

        [self.sectionChanges removeAllObjects];
        [self.objectChanges removeAllObjects];

    }
    else if (totalChanges < 1)
    {
        [tableView reloadData];
    }
}

- (NSMutableArray *)sectionChanges
{
    if (!_sectionChanges)
        _sectionChanges = [NSMutableArray new];

    return _sectionChanges;
}
- (NSMutableArray *)objectChanges
{
    if (!_objectChanges)
        _objectChanges = [NSMutableArray new];

    return _objectChanges;
}

请注意,此解决方案并不完美,因为如果部分发生更改并且这些对象位于未更新的部分中,它不会更新对象。应该很容易修复(并且与许多应用程序无关)。

于 2013-06-05T08:48:31.263 回答
1

我会打电话reloadData来的controllerDidChangeContent:

为了对表格的个别更改进行动画处理,Apple 的样板代码(iOS SDK 4.3.x)如下所示:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView beginUpdates];
}

- (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:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (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:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView endUpdates];
}
于 2010-02-02T09:57:59.197 回答
0

您可以记下数据源中的最后一个索引路径,然后执行此操作 -

    NSIndexPath *indexPath     = nil;
    NSMutableArray *newResults = [[NSMutableArray alloc] init];
    if(gLastResultIndex < [self.dataSource count])
    {
        for(int i=(gLastResultIndex); i<[self.dataSource count]; i++)
        {
            indexPath = [NSIndexPath indexPathForRow:i inSection:0];
            [newResults addObject:indexPath];
        }
        [self.table beginUpdates];
        [self.table insertRowsAtIndexPaths:newResults withRowAnimation:UITableViewRowAnimationNone];
        [self.table endUpdates];
    }
    [newResults release];

这是有选择地将新行添加到您现有的UITableView. reload table 重新加载表格中您可能不需要的所有单元格。我仅在整个数据源更改时才使用重新加载表...

于 2011-09-01T07:21:27.340 回答