UndoManager和多个MOC

时间:2014-02-14 14:08:24

标签: ios objective-c core-data nsmanagedobjectcontext nsundomanager

我有3个MOC。

  1. MainThread MOC显示内容(使用undomanager)
  2. 背景 - 保存MOC以将数据保存到光盘(连接到商店)
  3. Backgorund-update MOC从服务器下载数据,解析并稍后保存
  4. 他们是亲子关系。

    1. 背景更新 - > 1. MainThread - > 2.背景保存(商店)
    2. 现在当我从后台下载数据时,我需要在mainthread上禁用undomanager,这样它们就不会撤消 - 这可能是用户同时编辑内容的情况。

      现在的问题是,这是否正确。我在后台更新线程中有该代码

       //create child background context which is child of 1. MainThread
       NSManagedObjectContext* context = [[AppManager sharedAppManager] createChildManagedObjectContext];
       //I'M DOING ALL CHANGES ON DATA HERE
       [context.parentContext.undoManager disableUndoRegistration]; //disable undo on main thread
       [context save:nil]; //save changes to background thread
       [context.parentContext save:nil]; //save changes to main thread
       [context.parentContext processPendingChanges]; //process changes on main thread
       [context.parentContext.parentContext save:nil]; //save data to disc on 3. save-thread
       [context.parentContext.undoManager enableUndoRegistration]; //enable undo again
      

      使用块看起来像:

      [context.parentContext performBlockAndWait:^{
                  [context.parentContext.undoManager disableUndoRegistration];
      
                  [context performBlockAndWait:^{
                      [context save:nil];
                  }];
      
                  [context.parentContext save:nil];
                  [context.parentContext processPendingChanges];
      
                  [context.parentContext performBlockAndWait:^{
                      [context.parentContext.parentContext save:nil];
                  }];
      
                  [context.parentContext.undoManager enableUndoRegistration];
              }];
      

      我在问,因为我偶尔会遇到一些不一致的崩溃事件而且我找不到合理的原因。

1 个答案:

答案 0 :(得分:3)

首先,关于发布代码的一些基本观察。

  1. 在绝对必要时,您应该只使用performBlockAndWait ...这几乎不会。

  2. 您正在子上下文中调用performBlockAndWait,而在父上下文中调用performBlockAndWait。你应该从不那样做。

  3. 使用performBlockAndWait在具有专利背景的上下文中调用save:几乎可以保证不会按照您的想法执行操作。它只是保存到父上下文。

  4. 您在相同上下文的performBlockAndWait内呼叫performBlockAndWait。没错,因为那个电话是可以重入的。但是,另一条线索是您的CD堆栈管理存在问题。

  5. 现在,一些建议可能有所帮助。

    在您的情况下,我建议更改您的MOC层次结构。将专用队列MOC保留为主队列MOC的父级。这允许您的数据库更改异步完成。那里没有错。请记住,您必须将save:调用级联到父级或安排保存,因为保存主MOC只会将其数据从堆栈复制到父上下文,并且不会触及底层数据库。

    但是,我会将该背景作为MOC并将其作为主要MOC的子项删除。现在,您根本不必担心撤消管理器,您可以不管它。

    说到撤消管理器,我发现最好的撤消管理器是子上下文。我只想创建一个上下文,它是主要上下文的子项,在那里做我所有的更改。如果更改被放弃,只需删除上下文。一切都没有了。您可以在该上下文中安装撤消管理器以进行增量撤消管理。

    现在,如何处理正在执行某种类型的异步更新的背景上下文(可能来自某些Web服务)。我建议:

    1. 将其父级设置为与主MOC相同。您需要刷新主MOC以更改父级。这样做的缺点是,对数据库的任何更新都通过相同的父MOC进行同步,从而为主MOC提供了更多机会在获取时等待。

    2. 将其直接连接到持久性商店协调员,并使用通知合并更改。

    3. 最后,重新访问您的设计,看看是否可以通过异步调用。你真的应该可以通过拨打performBlock来解决这个问题,并且只能在非常罕见的情况下拨打performBlockAndWait