2012-07-25 83 views
1

我有一個iPad應用程序,我正在使用與核心數據NSUndoManager。事情通常很好,除了當我多次撤消/重做時有一個半可重現的錯誤。我只在主線程上工作(至少,我已禁用MagicalRecords在輔助線程上使用NSManagedObject。如果我嘗試撤銷/重做NSManagedObject到上下文的插入,問題總是會發生。CoreData拋出異常與NSUndoManager

我有這樣的事情:

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

而且幾次之後,我得到以下異常它發生在一個輔助線程,這讓我覺得核心數據在後臺做一些

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 

有時候我也是開玩笑g EXEC_BAD_ACCESS,其他時候只是上面的例外。

任何想法可能會造成這種情況?

編輯:爲澄清曼迪情況(見註釋)

+0

您需要給予更多的上下文,而不僅僅是對「撤銷」的調用。 – Mundi 2012-07-25 20:54:21

+0

當撤消發生時,我重建UI,這是一個非常昂貴的操作(從原始的NSManagedObjects重建大量的自定義UIViews)。這最終會被優化。在這裏很難提供一段代碼(這是一個大型項目) - 對你有用嗎? – 2012-07-25 20:56:27

+0

你在撤消什麼? – Mundi 2012-07-25 22:02:33

回答

0

這裏是停在我所有的崩潰的解決方案: 顯然神奇紀錄默認使用privateQueue併發性,如果你的代碼是不是線程安全的,我想的東西不工作了。我所做的是從NSPrivateQueueConcurrencyType改變NSMainQueueConcurrencyType以下方法:

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

我還發現了另一個細節,在這裏工作: Core Data deleteObject: sets attributes to nil

我有什麼需要做的就是將之前保存的管理對象上下文/刪除一個管理對象。有點怪異和低效率,但節省很多麻煩。

0

標準的方式來撤銷管理對象的插入是

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

無需使用undo機制。這樣,你的代碼變得

  • 更具可讀性(你說你明確地想要做什麼)和
  • 不易出錯(無不可預見的更復雜的API事件)。
+0

如果我對撤銷操作的其餘部分使用了撤消管理器,那麼如何攔截刪除操作並處理該自定義操作?似乎我將不得不跟蹤我自己的撤銷/重做堆棧 – 2012-07-26 21:18:09

+0

好吧,我誤解了你在做什麼。怎麼樣,在「陷阱!」部分,你只需在另一個線程上調度撤銷? – Mundi 2012-07-26 21:22:45

+0

它似乎再也不會碰到陷阱部分了。我試圖找出一個很好的方式來知道Core Data何時處理完畢。我在撤消之前嘗試調用processChanges,但這似乎沒有幫助。我甚至嘗試了執行一個performSelect:withDelay:0以在撤消管理器當前撤銷/重做的情況下跳到下一個運行循環: if(self.undoManager.isUndoing || self.undoManager.isRedoing) { NSLog (@「問題在這裏!跳過」); [self performSelector:@selector(didRedoChange :) withObject:notification afterDelay:0]; } – 2012-07-26 21:33:05