2

我有3个MOC。撤消管理器和多个MOC

  1. MainThread MOC显示的东西(带的UndoManager)
  2. 背景保存MOC来保存数据到光盘(连接到存储)
  3. Backgorund更新MOC从服务器下载数据,分析它并保存后

他们是亲子关系。

  1. 背景更新 - > 1. MainThread - >背景保存(存储)

现在,当我从后台我需要在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]; 
     }]; 

我这么问是因为偶尔我得到了一些不一致的崩溃,我真的不能找到一个理由对于那些。

回答

3

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

  1. 只应用户performBlockAndWait在绝对必要的...这是几乎从来没有。

  2. 您在子上下文中调用performBlockAndWait,而在父上下文中调用performBlockAndWait。你应该从来没有做到这一点。

  3. 使用performBlockAndWait在具有专利上下文的上下文中调用​​几乎可以保证不会做你认为它的工作。它所做的只是保存到父上下文。

  4. 您在performBlockAndWait内调用performBlockAndWait,而在同一上下文中调用performBlockAndWait。因为这个电话是可重入的,所以没什么不对。但是,另一个线索是您的CD堆栈管理有问题。

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

在你的情况下,我会建议改变你的MOC层次结构。将专用队列MOC保留为主队列MOC的父代。这可以让您的数据库更改异步完成。那里没有错。请记住,您必须将调用​​级联到父级,或者计划一次保存,因为保存主MOC只会将其数据复制到父级上下文,而不会触及底层数据库。

但是,我会把这个背景MOC作为主要MOC的孩子去除。现在,你根本不必担心撤销管理器,你可以放弃它。

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

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

  1. 设置它的父母与主要的MOC相同。您需要刷新主要MOC,以更改父级。这具有缺点,即对数据库的任何更新都通过相同的父MOC进行同步,从而为主MOC提取更多机会等待。

  2. 将它直接连接到持久存储协调器,并使用通知合并更改。

最后,重新审视你的设计,看看你是否可以通过异步调用。在极其罕见的情况下,您真的应该能够拨打performBlock,并且只能拨打performBlockAndWait

+0

嗨,谢谢你的提示。我正在使用performBlockAndWait,因为我在压力测试应用程序期间可以产生一些崩溃。在主线程中进行压力测试EDIT/SAVE时,在背景中进行更新。随着performBlock UndoManager进入一些不稳定的状态,并在该过程中崩溃。我会通读您的评论,并根据您的建议重新考虑我的解决方案 - 我可能会对此有所疑问,但需要先分析它:) –

+0

如果'performBlockAndWait'可以防止崩溃......这意味着您在同步问题中其他可能在不阻碍操作的情况下解决的领域。 –

+0

接受答案 - 花了我一段时间找到解决方案,但我最终扔掉undomanager和做的东西在单独的上下文,我扔掉了,如果用户取消。这解决了我的大部分问题,thx的想法。 –