防止 NSManagedObject 引用更新 UITableViewCell

Posted

技术标签:

【中文标题】防止 NSManagedObject 引用更新 UITableViewCell【英文标题】:Preventing an NSManagedObject reference updating a UITableViewCell 【发布时间】:2017-12-21 10:35:13 【问题描述】:

背景信息:

我们有一个从 Core Data 填充表格视图的应用程序。这个应用程序实现了一个同步机制,它在后台上下文中更新 CoreData 数据,并在完成后自动合并回主上下文。

为了简单起见,让我们假设一个 Message 和一个 Comment '实体',其中消息可以有零个或多个评论。我们为所有实体都继承了 NSManagedObjects 子类,因此在 Message 类中有一个名为 comments 的属性(类型为 Set<Comment>)。

应用程序的一个要求是视图可以在导航到新屏幕时更新屏幕上的数据。这意味着当您在屏幕上并且任何数据在后台更新时,可见数据应该保持相同

我们的MessageViewcontroller 有一个私有属性message,它被填充到viewDidLoad。在cellForRowAt indexPath 中,我们使用cell.message = message.comments[indexPath.row]

问题:

这样做的问题是,如果我们在后台上下文中更新了评论,该评论被合并回主上下文,则在 tableview 中上下“滚动”(再次触发cellForRowAt indexPath)将更新单元格带有更新的文本。

这是有道理的,因为我们的message 属性是一个引用,它代表我们CoreData 中的数据。

问题:

如何防止message 变量更新?或者换一种说法:如何在加载视图控制器时保留消息对象(及其关系)的“快照”?

解决方案?

我认为唯一可行的解​​决方案是创建一个具有相同属性的结构并在加载视图时填充它。我不太喜欢这种方法,因为我们的模型比Message 示例复杂得多,并且有很多关系、递归等。

【问题讨论】:

【参考方案1】:

ios 9 开始,您可以使用 queryGenerationTokens。生成令牌是指向核心数据在特定时间所处的状态的指针。您创建一个直接附加到持久存储协调器的新主队列 managedObjectContext 并将其 queryGenerationToken 设置为当前队列。还将 automaticallyMergesChangesFromParent 设置为 false。在这个新上下文上执行您的提取,您将不会从核心数据发生的任何其他事情中获得任何更新或更改。当用户离开页面时,你可以丢弃上下文,当他回到页面时,你可以创建一个新的。上下文不是资源密集型的,您不必害怕根据需要创建和丢弃它们。

【讨论】:

非常感谢您的回答。我以前从未听说过queryGenerationTokens,但看起来这正是我所需要的。我试试看! 看起来它运行良好。我现在使用persistentContainer.newBackgroundContext() 并在需要更新时使用ctx.setQueryGenerationFrom(NSQueryGenerationToken.current) 固定它的生成。看起来我什至不需要将automaticallyMergesChangesFromParent 设置为false,或者我应该设置它只是为了确保?我注意到的一件重要的事情是,我需要在更改世代后调用ctx.refreshAllObjects() (source) 才能看到更改后的数据。 仅供参考:automaticallyMergesChangesFromParent 的文档指出:“不支持将上下文固定到非当前查询生成时将此属性设置为 YES。”

以上是关于防止 NSManagedObject 引用更新 UITableViewCell的主要内容,如果未能解决你的问题,请参考以下文章

应更新数据时,NSManagedObject 的删除/插入与更新

在 Swift 中将 NSManagedObject 添加到 CoreData 多对多关系时防止循环

每次更新服务引用时,如何防止 VS2010 创建新绑定?

从 NSValueTransformer 内部引用 NSManagedObject 实体

存储对已删除 NSManagedObject 的引用的局部变量会发生啥

将对 NSManagedObject 的属性的引用传递给后台线程