UIManagedDocument父上下文对象插入后台优先级队列,不使用子上下文在UI中更新

时间:2014-06-19 09:11:23

标签: ios multithreading core-data nsmanagedobjectcontext uimanageddocument

我试图在我的应用程序中实现一些基本的UIManagedDocument导入/导出功能,主要用于开发,以便我可以轻松检查文档内容,更重要的是在我开始尝试迭代时保留一组测试数据我的CoreData模型。

我要做的就是从本地文件加载一些JSON数据并将其注入我的应用程序UIManagedDocument。 UIManagedDocument的ManagedObjectContext内容在我的应用程序中使用来自斯坦福iOS课程的一些核心数据表视图控制器可视化。

我想我会尝试用一些线程编写这个来保持UI响应并学习如何做到这一点。所以我做过类似的事情

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
  // read JSON data file
  // parse JSON into dictionaries etc
  // iterate over dictionaries
  // try to create a new core data entity with my document's ManagedObjectContext
} );

起初我觉得这很有效。没有错误,断言,崩溃触发,在查看我的CoreData TableViews时,我可以在UI中看到新添加的对象。不幸的是,新添加的对象似乎从未保存回商店。我甚至连接起来听我的UIDocument的managedObjectContext中的NSManagedObjectContextDidSaveNotification,并看到它在按下主页按钮时没有触发,就像它通常在我的UI待处理的应用程序中执行了一些更改一样。事实上即使在UI中执行这些操作也不会导致通知和保存发生,因此显然不满意。

我从后台队列中展开代码并在主线程上同步运行它,一切正常,新数据保存正确。

我开始阅读线程和coredata的复杂性,文档似乎建议使用UIDocument的ManagedObjectContext的父ManagedObjectContext在后台执行操作,所以我尝试使用这个再次执行相同的代码父上下文,如下

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
  // read JSON data file
  // parse JSON into dictionaries etc
  // iterate over dictionaries
  // try to create a new core data entity with my document's ManagedObjectContext parent ManagedObjectContext
} );

这次出于某种原因,CoreData TableView控制器不再更新以显示新注入的对象。即使在父上下文中显式调用save之后,也没有出现任何内容。但是在退出应用程序并重新加载应用程序时,新注入的对象似乎确实正确添加。有趣的是,在这一点上,我留下了一个带有指定cachename的fetchrequest,并且在以这种方式注入对象后,在应用程序的第一次运行时抛出了一个错误。我猜不知道对象来自父上下文的方式可能会以某种方式使缓存失效,这仍然是我不完全理解的东西。即使将缓存更改为nil也没有解决表视图问题没有更新与将对象注入父上下文时相同的会话。

在其他地方看到我已经看到了managedObjectContext的一些用法建议。有人说你必须打电话的另一个案例

[document updateChangeCount:UIDocumentChangeDone]

在所有更改之后确保执行保存,或者使用

- (void)autosaveWithCompletionHandler:(void (^)(BOOL success))completionHandler

代替。虽然在其他地方我已经看到提到保存应该足以通过层次结构推送上下文内容。保存仅适用于儿童 - >父母而非父母 - >子。

或者我只是做错了?

任何人的时间和帮助都非常感谢!欢呼声。

2 个答案:

答案 0 :(得分:0)

请查看“家长/儿童语境”' Multi-Context CoreData中的部分。

  

每当儿童MOC保存时,父母就会了解这些变化,这也会导致获取的结果控制器被告知这些变化。然而,由于背景MOC不了解PSC,因此尚未保留数据。要将数据传输到磁盘,您需要在主队列MOC上添加额外的saveContext:

我按照以下方式保存到PSC:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
{
    // read JSON data file
    // parse JSON into dictionaries etc
    // iterate over dictionaries

    NSError* error;
    if (self.managedObjectContext.hasChanges)
    {
        [self.managedObjectContext save: &error];
    }

    // Save main context
    dispatch_sync(dispatch_get_main_queue(), ^
    {
        [[AXContextHelper sharedInstance] saveMainContext];
    });
}

答案 1 :(得分:0)

在查看了我可以找到的类似问题的所有建议后,他们似乎都没有帮助。

我最后描述的场景是文件存储处理正常,但UI没有更新。当我执行此导入/导出时,我在核心数据表视图控制器的顶部视图中,在我注入所有这些JSON对象时不会更新,所以最后我所做的就是强制该控制器重新获取它的数据。我相信NSFetchedResultsController旨在监视managedObjectContext并根据需要更新获取请求。无论出于何种原因,这都不起作用。

随着强制重新获取调用,一切似乎都正常。新注入的实体出现在我的表中,并保存到商店文件中。

这些对象中有一些错误,或者我仍然使用它错了但我看到其他问题......我的导入/导出数据现在都在父背景的后台线程上工作。我今天注意到的是,我可以使用UI在主线程上使用子上下文正确插入和编辑一些对象。在进行这些编辑之后,我不会故意调用任何内容,所以我猜编辑仍在等待,直到核心数据决定保存。如果我然后转到我的导出功能并使用父上下文使用它然后我发现新编辑或插入的对象不在那里。

显然,从孩子那里没有及时发送消息 - >父本,以及来自父本身的后台线程编辑的消息传递似乎无法正常工作..我从未收到任何关于我在父上下文中的线程中执行的编辑的通知,即使它们似乎有效。如果我通过文档强制保存,那么传入的词典显示没有进行编辑,即使编辑被正确保存到存储文件中。

我想我现在需要强制我的文档在每次操作后保存,或者至少在我要在另一个线程上执行的每个操作之前保存,以确保父/子都同步。

我最初描述的问题仍然是设法绕过,但我仍然想知道我应该如何使用UIManagedDocument的父和子上下文来避免遇到这些问题。