【问题标题】:CoreData throws exception with NSUndoManagerCoreData 使用 NSUndoManager 抛出异常
【发布时间】:2012-07-25 20:48:47
【问题描述】:

我有一个 iPad 应用程序,我在其中使用 NSUndoManager 和 Core Data。事情通常运作良好,除了当我多次撤消/重做时有一个半可重现的错误。我只在主线程上工作(至少,我已禁用 MagicalRecords 在辅助线程上使用 NSManagedObject。如果我尝试撤消/重做 NSManagedObject 到上下文的插入,问题总是会发生。

所以我有这样的事情:

if (!self.undoManager.isUndoing && !self.undoManager.isRedoing) 
{
    [self.undoManager undo];   
}
else 
{
    NSLog(@"gotcha!");
}

几次之后,我得到以下异常。它发生在辅助线程上,这让我觉得 Core Data 正在后台做某事。

CoreData: error: Serious application error.  Exception was caught during Core Data
change processing.  This is usually a bug within an observer of 
NSManagedObjectContextObjectsDidChangeNotification.  _registerUndoObject:: NSUndoManager 
0xcea2d60 is in invalid state, must begin a group before registering undo
with userInfo (null) 2012-07-25 15:42:26.850 TT[3972:3c07] *** Terminating app due to 
uncaught exception 'NSInternalInconsistencyException', reason: '_registerUndoObject::
NSUndoManager 0xcea2d60 is in invalid state, must begin a group before registering undo

有时我也会得到 EXEC_BAD_ACCESS,其他时候只是上述异常。

知道是什么原因造成的吗?

编辑:澄清了 Mundi 的情况(见 cmets)

【问题讨论】:

  • 除了调用undo之外,您还需要提供更多上下文。
  • 当撤销发生时,我重建 UI,这是一个相当昂贵的操作(从原始 NSManagedObjects 重建大量自定义 UIView)。这最终将被优化。在这里提供一段代码会很困难(这是一个大项目)——什么对你有用?
  • 我正在撤消 NSManagedObject 的插入。这似乎是最常发生崩溃的情况之一

标签: ios core-data nsundomanager


【解决方案1】:

撤消托管对象插入的标准方法是

[self.managedObjectContext deleteObject:theManagedObject];
// If you have saved already, you would need to save again.

无需使用撤消机制。像这样,你的代码变成了

  • 更具可读性(你明确地说出你想做什么)和
  • 更不容易出错(没有更复杂的 API 的意外事件)。

【讨论】:

  • 如果我在其余的撤消操作中使用撤消管理器,您将如何拦截删除操作然后处理该自定义操作?看来我必须跟踪我自己的撤消/重做堆栈
  • 好吧,我误解了你在做什么。怎么样,在“陷阱!”部分,你只是在另一个线程上分派撤消?
  • 似乎再也没有遇到问题了。我正在尝试找出一个好方法来了解 Core Data 何时完成处理内容。我尝试在撤消之前调用 processChanges,但这似乎没有帮助。我什至尝试执行 performSelect:withDelay:0 在 undoManager 当前正在撤消/重做的情况下跳到下一个运行循环: if (self.undoManager.isUndoing || self.undoManager.isRedoing) { NSLog(@"issue在这里!跳过"); [self performSelector:@selector(didRedoChange:) withObject:notification afterDelay:0]; }
  • 我感觉正常的摇晃手势不会发生这种情况,因为这让设备有足够的时间来处理所有事情。唯一似乎可以修复它的方法(虽然是一种 hack)是禁用撤消/重做按钮 1/2 秒以防止连续点击。
  • 撤消插入后我现在遇到了这个问题。
【解决方案2】:

这是阻止我所有崩溃的解决方案: 显然 Magical Records 默认使用 privateQueue 并发,如果你的代码不是线程安全的,我想事情不会成功。我所做的是将它从 NSPrivateQueueConcurrencyType 更改为 NSMainQueueConcurrencyType 用于以下方法:

+ (NSManagedObjectContext *) MR_contextWithoutParent;
{
    NSManagedObjectContext *context = [[self alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
return context;
}

我还发现了另一个在这里起作用的细节: Core Data deleteObject: sets attributes to nil

我必须做的是在添加/删除托管对象之前保存托管对象上下文。有点奇怪和低效,但省去了很多麻烦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    相关资源
    最近更新 更多