【发布时间】:2011-03-25 20:23:04
【问题描述】:
在后台线程保存其上下文后,NSManagedObject 无法反映对持久存储所做的更改。
设置
在一个简单的测试应用程序中,我有一个单独的窗口,其中列出了我的核心数据持久存储中的所有对象、一个用于过滤结果的搜索框和一个用于显示所选项目名称并允许名称改变。
绑定如下:
ArrayController --> AppDelegate --> ManagedObjectContext TableView Col 1 --> ArrayController --> 值 --> 排列对象.widgetName TableView Col 2 --> ArrayController --> 值 --> mappedObjects.uid SearchField --> ArrayController --> 谓词 --> filterPredicate TextField --> ArrayController --> value --> selection.widgetName我还有一个按钮,用于启动后台 (NSOperation) 从 Web 服务器获取数据。
过程
当用户单击刷新按钮时,会启动一个 NSOperation,它会异步抓取小部件、解析响应、检查本地小部件以删除响应中的内容、添加未存储在本地的新小部件以及应该使用从服务器检索到的数据进行更新的现有本地小部件。
处理完成后,使用以下命令通知主上下文:
[mainContext performSelectorOnMainThread:
@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
我在主控制器中有一个观察者进行测试,显示更改进行得很好,并且主控制器得到了通知。
问题
如果我使用文本字段对选定对象进行更改,当后台线程上的数据被保存时,UI 中的对象不会更新以反映这些更改(即它不会用从服务器更改)。
例如,给定以下三个小部件和 ID:
测试名称 1 |编号 123 测试名称 2 |编号 234 测试名称 3 |编号 345如果我在 Test Name 2 的 UI 中将名称更改为 Renamed 2 我有以下内容:
当我在后台刷新时,我希望列表反映服务器的状态,即返回:
测试名称 1 |编号 123 测试名称 2 |编号 234 测试名称 3 |编号 345它仍然存在:
测试名称 1 |编号 123 重命名 2 |编号 234 测试名称 3 |编号 345我知道持久存储已更新,因为如果我从 XCode 中终止应用并重新启动,则会显示所需的信息。如果我正常退出应用程序,更改的值会在应用程序关闭时写入商店,重新打开会显示重命名的值。
我的尝试
我知道消息正在从后台发送到主上下文,并且我知道数据正在保存到存储中。因此,我认为的问题是主上下文没有像我期望的那样合并,或者我需要以某种方式强制数组控制器从持久存储中获取并丢弃它的上下文。
- 我在商店保存通知时尝试了
processPendingChanges:,但我怀疑我只是将Renamed 2写到商店。 - 我曾尝试在阵列控制器上执行
rearrangeObjects,但由于阵列控制器正在处理主要上下文,我怀疑这无济于事 - 我尝试在数组控制器上执行
fetch:nil以从持久存储中获取数据,但我再次怀疑主上下文正在覆盖Renamed 2的值,因为它尚未保存。李> - 我已经按照 Apple 文档在阵列控制器上尝试了
fetchWithRequest:nil merge:NO error:&error,但这似乎并没有改变显示的值
我认为需要发生的是数组控制器在我写入后台存储数据之前将其数据保存到持久存储中,以便数组控制器上的获取将导致数据根据我的期望准确。如果确实如此,我将如何告诉数组控制器执行此操作,或者如果主 managedObjectContext 以某种方式保存,数组控制器是否会通过绑定简单地知道更改?
我可以通过从持久存储中获取数据、将该数据放入数组并在数组控制器上执行setContent: 来破解解决方案,然后在保存持久存储时重复此操作,但这感觉完全不对,更不用说必须跟踪阵列控制器的选定状态(以及可能由于该主选择而发生的任何子阵列选择)的问题。
我离开基地了吗?我显然在这里遗漏了一些东西。
非常感谢任何智慧或建议的话语。
【问题讨论】:
标签: objective-c cocoa-bindings nsarraycontroller background-process nsmanagedobjectcontext