NSFetchedResultsController 在托管对象被修改时通知其委托删除更改,并且从不通知插入或更新

Posted

技术标签:

【中文标题】NSFetchedResultsController 在托管对象被修改时通知其委托删除更改,并且从不通知插入或更新【英文标题】:NSFetchedResultsController notifies its Delegate of delete changes when a managed object is modified, and never notifies for Insert or Update 【发布时间】:2016-06-01 21:43:12 【问题描述】:

我有一个UITableViewController,它是NSFetchedResultsController 的代表。我的NSFetchedResultsControllerDelegate 函数是根据Apple's documentation 中的“典型用途”设置的,表格视图控制器作为获取的结果控制器的委托属性。

我还有一些视图控制器,它们显示在可以修改托管对象的表视图顶部。这些修改是在 same 托管对象上下文中完成的。我的应用程序中只构建了一个托管对象上下文,并且可以全局访问它。 (我在对象上下文构造中放置了一些 print 语句,以确保我不会意外地在其他地方重新构造它。)

当我修改其中一个托管对象时,会调用委托函数controller:didChangeObject,但NSFetchedResultsChangeType 总是 .Delete。当我创建一个托管对象时,委托函数根本不会触发。

但是,当我手动调用 call performFetch()tableView.reloadData() 时,单元格会恢复到正确的状态:删除的行又回来了,所有未插入的行都会创建。

结果是删除对象按预期工作(删除单元格),但对对象的更新会导致其单元格被删除,并且对象创建不会触发单元格插入。

我尝试为这种行为创建一个简单的演示,但是当我从一个空白应用程序重新创建这种情况时,我看不到这种行为。所以我的应用程序中的某些东西导致了这种奇怪的行为,但我不知道是什么。有什么想法吗?


额外信息:

谓词和排序描述符的实际构造是在几个不同的类上完成的,但是通过print(resultsController.fetchRequest.predicate)print(resultsController.fetchRequest.sortDescriptors) 打印它们会得到以下结果:

可选(readState == "2" OR readState == "1")

可选([(readState,升序,比较:),(标题,升序,比较:)])

我在我的controller:didChangeObject: 方法中添加了一个打印语句,我可以看到它只被type.rawValue = 2(即.Delete)调用,并且仅在我修改对象时调用,而不是在我创建对象时调用。

【问题讨论】:

如果在更新时删除了单元格,如果与实际上下文内容不匹配,我希望您会崩溃...我想您应该删除 SQL 文件并重试。然后删除并重新创建模型。我认为对此没有合理的解释...... 您是否为 FRC 指定谓词?如果是这样,更新是否会导致对象被谓词排除,从而从 TV 中删除? @pbasdf 好主意,但在这种情况下不是解决方案。我确实指定了一个谓词,但这不会阻止对象被包含在内。当我重新获取并在表上调用 reloadData 时(仍然使用谓词),单元格返回 请向我们展示您的 FRC 初始化代码,特别是 predicate 构造部分。 好吧,也许这会有所帮助:***.com/a/12514826/826716。这是关于具有关系使用的复杂排序描述符。根据我的经验,它也发生在谓词上。因此,如果您可以向我们展示您的实际谓词和排序描述符 - 它可能有助于确定这种不当行为的根源。在 FRC 分配行和po fetchRequest.predicatepo fetchRequest.sortDescriptors 处设置断点。 【参考方案1】:

这与NSFetchedResultsController 处理其NSPredicate 的方式不一致。

如果NSFetchedResultsController 是由一个获取请求构造的,该请求具有一个谓词,该谓词在整数和字符串之间进行比较,如下所示:

let predicate = NSPredicate(format: "integerAttribute == %@", String(1))

这将导致谓词字符串为:

integerAttribute == "1"

在这种情况下,初始提取工作正常:在提取结果控制器上调用函数 performFetch() 返回所有对象,其中 integerAttribute 等于 1(其中 integerAttribute 的类型为 Int32 )。

但是,NSFetchedResultsControllerDelegate 的通知无法正常工作。托管对象的修改会导致代理收到NSFetchedResultsChangeType.Delete 更改的通知。托管对象的创建根本不调用委托。

要消除所有这些怪异现象,请按如下方式修复谓词格式字符串:

let predicate = NSPredicate(format: "integerAttribute == %d", 1)

【讨论】:

以上是关于NSFetchedResultsController 在托管对象被修改时通知其委托删除更改,并且从不通知插入或更新的主要内容,如果未能解决你的问题,请参考以下文章

在 Core Data 应用程序中调用 performFetch 后,是不是需要手动更新表视图?