【问题标题】:"didChangeSection:" NSfetchedResultsController delegate method not being called“didChangeSection:” NSfetchedResultsController 委托方法没有被调用
【发布时间】:2011-06-05 23:35:02
【问题描述】:

我有一个标准的拆分视图控制器,带有一个详细视图和一个表格视图。在详细视图中按下按钮可以导致对象更改其在表格视图中的排序位置。只要由此产生的排序更改不会导致添加或删除部分,这就可以正常工作。 IE。一个对象可以改变它在一个部分中的顺序或从一个部分切换到另一个部分。这些订购更改可以正常工作而不会出现问题。但是,如果对象试图移动到尚不存在的部分,或者是离开部分的最后一个对象(因此需要删除其离开的部分),则应用程序崩溃。

NSFetchedResultsControllerDelegate 具有处理添加和删除部分的方法,这些部分应在这些情况下调用。但是由于某种原因没有调用这些委托方法。

有问题的代码是样板:

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

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
NSLog(@"didChangeSection");

    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 {    
NSLog(@"didChangeObject");

    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 {
NSLog(@"didChangeContent");
    [self.tableView endUpdates];

    [detailViewController.reminderView update];
}

启动应用程序,然后使最后一个对象离开一个部分会导致以下输出:

2011-01-08 23:40:18.910 Reminders[54647:207] willChangeContent
2011-01-08 23:40:18.912 Reminders[54647:207] didChangeObject
2011-01-08 23:40:18.914 Reminders[54647:207] didChangeContent
2011-01-08 23:40:18.915 Reminders[54647:207] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1145.66/UITableView.m:825
2011-01-08 23:40:18.917 Reminders[54647:207] Serious application error.  Exception was caught during Core Data change processing: Invalid update: invalid number of sections.  The number of sections contained in the table view after the update (5) must be equal to the number of sections contained in the table view before the update (6), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted). with userInfo (null)

如您所见,“willChangeContent”、“didChangeObject”(移动相关对象)和“didChangeContent”都被正确调用。根据 Apple 的 NSFetchedResultsControllerDelegate 文档,“didChangeSection”应该在“didChangeObject”之前被调用,这样可以防止导致崩溃的异常。

所以我想问题是我如何确保 didChangeSection 被调用?

提前感谢您的帮助!

【问题讨论】:

    标签: ipad ios core-data nsfetchedresultscontroller


    【解决方案1】:

    此问题是由使用临时属性作为 sectionNameKeyPath 引起的。当我将用于 sectionNameKeyPath 的属性存储在数据库中时,问题就消失了。我不知道当使用瞬态属性作为 sectionNameKeyPath 时,是否有办法根据 NSFetchedResultsController 内容更改来更新部分。目前我认为这是瞬态属性的限制。

    【讨论】:

    • 我的项目中有一个非常相似的问题。 didChangeSection 似乎没有在应该调用的时候被调用。我对 sectionNameKeyPath 使用“objectID.URIRepresentation”,因为我希望每个对象都在自己的部分中。我正在 iPhone 5.1 模拟器中进行测试。我的 FRC 根据值(从递增到递减)进行排序,因此如果对象的值发生变化,我的部分的顺序也应该发生变化,但 didChangeSection 函数永远不会被调用。您对为什么会发生这种情况有任何直觉吗?谢谢。
    • 我也为此苦苦挣扎,起初为 sectionNameKeyPath 指定 nil 。当所有对象都被删除时,tableView 的数据源方法(fetchedObjects == 0)中的节数返回 0,这破坏了 tableView。如果您需要触发此委托方法,则应该指定某种 sectionNameKeyPath。这现在看起来很明显,只是想我会为那些像我一样木头的人分享。
    • 我遇到了一个非常相似的问题,我们的不同之处在于您使用的是瞬态属性,而我没有使用数据模型中的任何属性根本 - 我有一个仅在类别中的属性,所有 willAccess...didChange 的东西都有自定义的 getter 和 setter。一切似乎都很完美,但永远不会调用didChangeSection。为我解决的是最终创建一个瞬态属性来表示它。然后我可以删除我的自定义设置器并稍微调整我的自定义获取器以使用 -primitiveValueForKey:.
    【解决方案2】:

    我在我的应用程序中做同样的事情(sectionNameKeyPath 中的瞬态属性)并且没有看到您遇到的问题。我正在 iOS 4.2.1 上对此进行测试...有一个已知错误,您无法信任 iOS 3.X 中的任何 FRC 委托回调,您必须在 controllerDidChangeContent: 消息中执行完整的 [tableView reloadData]。 see the FRC documentation

    我已经测试过从包含另一个条目的现有部分到不存在的部分,以及从只有一行的部分到另一个不存在的部分。

    【讨论】:

    • 感谢布伦特指出这一点。我使用的是 iOS 4.1,所以我很可能遇到了一个已经修复的错误。
    • 你在模拟器中也有同样的行为吗?你试过以后的版本吗? (我有私心,因为我依赖此功能,我不希望客户向我报告错误;)遗憾的是,我已将所有 iDevice 更新到最新版本。
    • 嗨,布伦特,最初的问题是在模拟器中发现和测试的。即,当我遇到此问题时,我从未在实际设备上尝试过该应用程序。仅供参考,我现在已经将 SDK 升级到 4.2 并最终恢复了瞬态属性,并且我不再遇到任何问题。这进一步证明这是 4.1 中的 SDK 问题
    猜你喜欢
    • 1970-01-01
    • 2013-12-03
    • 2020-11-28
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多