使用NSFetchedRequestController更新UITableView行和节,而不使用reloadData

时间:2014-07-08 06:30:20

标签: ios objective-c uitableview nsfetchedresultscontroller

我无法找到这个特定问题的答案,所以就是这样。

我在UITabBarController下有多个VC,每个都有一个UITableView并使用NSFetchedRequestController来获取数据。在每个VC中我都有一个refreshFetchedRequest方法,我在viewDidAppear上调用它来开始反映从一个VC到另一个VC的任何变化。它基本上只是一个performFetch。

这个问题可以通过在refreshFetchedRequest之后调用reloadData来轻松解决,但我想要行/节插入/删除动画。

所以总结一下viewDidAppear,我这样做:

[self refreshFetchedRequest];
[tableView beginUpdates];
// compare cached rows/sections with NSFetchedRequestController - how?
[tableView endUpdates];

我从哪里获取现有的缓存UITableView行和节以将它们与刷新的NSFetchedResultsController进行比较?

更新:

我现在在viewDidAppear方法中执行此操作:

NSFetchedRequestController *frcBeforeUpdate = frc;
[self refreshFetchedRequest]; // refreshes my frc property
[tableView beginUpdates];
// compare frcBeforeUpdate with frc here
[tableView endUpdates];

5 个答案:

答案 0 :(得分:1)

然后通过以下方式解决您的问题:

  • 两个viewControllers使用相同的managedObjectContext
  • 您监听managedObjectContextDidSave通知,并在您用于fetchedResultsController的managedObject上调用mergeChangesFromManagedObjectContextDidSaveNotification。

在这两种情况下,您都将获得您正在寻找的委托回调。

答案 1 :(得分:1)

好的,在重新阅读你的问题之后,我想我现在明白了你想要的东西:你希望tableview在动画再次出现之后更新动画。所以你想延迟对tableView的更新。

使用NSFetchedResultsController。而不是在tableView上调用相关的update-method来响应这些方法,而是将更改存储在NSDictionary或自定义类中,您可以在其中存储更改类型的索引路径。然后在viewDidAppear中,您将调用类似于:

的内容
[tableView beginUpdates]
for (NSIndexPath * anIndexPath in self.cachedChanges[updates]){
    [tableView reloadRowAtIndepath: anINdexPath];
}
for (NSIndexPath * indexPath in self.cachedChanges[deletions]){
    [tableView deleteRowAtindexPath: indexPath]
}
// ... more like this for sections and insertions
[tableView endUpdates];
self.cachedChanges = nil;

这是你在找什么?

答案 2 :(得分:0)

您必须将viewController设置为fetchedResultsController的委托。查看NSFetchedResultsController上的文档,它会显示可复制和匹配的代码,以完全按照您的意愿执行。

答案 3 :(得分:0)

您应该成为委托NSFetchedResultsController并按照以下方式处理委托的方法:

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

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    UITableViewRowAnimation animationType = UITableViewRowAnimationAutomatic;
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:animationType];
            break;

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

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableViewRowAnimation animationType = UITableViewRowAnimationFade;
    UITableView *tableView = self.tableView;

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:animationType];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:animationType];
            break;

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

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:animationType];
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:animationType];
            break;
    }
}

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

通过在Xcode上创建一个空的Master-Detail应用程序项目,您可以看到通过NSFetchedResultsController向表中添加新记录的一个很好的示例。

答案 4 :(得分:0)

- (void)animateRefreshFetchedResultsControllers
{
    NSFetchedResultsController *frc3 = _frc1;
    [self refreshFetchedResultsControllers];

    NSMutableArray *oldSectionNames = [NSMutableArray new];
    NSMutableArray *newSectionNames = [NSMutableArray new];
    for (id <NSFetchedResultsSectionInfo> section in frc3.sections) {
        [oldSectionNames addObject:section.name];
    }
    for (id <NSFetchedResultsSectionInfo> section in _frc1.sections) {
        [newSectionNames addObject:section.name];
    }

    [_tableView beginUpdates];
    NSMutableIndexSet *sectionsToDelete = [NSMutableIndexSet new];
    for (NSString *sectionName in oldSectionNames) {
        if (![newSectionNames containsObject:sectionName]) {
            [sectionsToDelete addIndex:[oldSectionNames indexOfObject:sectionName]];
        }
    }
    [_tableView deleteSections:sectionsToDelete withRowAnimation:UITableViewRowAnimationLeft];

    NSMutableIndexSet *sectionsToInsert = [NSMutableIndexSet new];
    for (NSString *sectionName in newSectionNames) {
        if (![oldSectionNames containsObject:sectionName]) {
            [sectionsToInsert addIndex:[newSectionNames indexOfObject:sectionName]];
        }
    }
    [_tableView insertSections:sectionsToInsert withRowAnimation:UITableViewRowAnimationRight];

    NSMutableArray *rowsToInsert = [NSMutableArray new];
    for (int i = 0; i < sectionsToInsert.count; i++) {
        id <NSFetchedResultsSectionInfo> section = _frc1.sections[i];
        for (int j = 0; j < section.numberOfObjects; j++) {
            NSIndexPath *rowIndexPath = [NSIndexPath indexPathForRow:j inSection:i];
            [rowsToInsert addObject:rowIndexPath];
        }
    }
    [_tableView insertRowsAtIndexPaths:rowsToInsert withRowAnimation:UITableViewRowAnimationRight];

    [_tableView endUpdates];
}