Resolution
NSUndoManager
must only be used in a child NSManagedObjectContext
(when used with Core Data). This is because the UIManagedDocument
may auto-save at any point in time, after which an undo
will have no effect. Therefore there is no point using NSUndoManager
to just achieve save/cancel functionality, since a child context will give you the same result.
Bit sad really, because NSUndoManager
is a lot easier to implement than a child context (for the latter I have to call existingObjectWithID
to copy objects from the parent to the child - painful). Personally I would have thought the document should not auto-save if groupingLevel != 0
. Rant finished.
Original Question
I have a table view controller that loads data using Core Data into a UIManagedDocument
. It segues to a view controller to edit each row in the table. In that view controller I have cancel and save buttons. I am implementing the cancel capability using NSUndoManager
through a category on my NSManaged
object (self.list
below).
- (void)viewDidLoad
{
[super viewDidLoad];
[self.list beginEdit];
}
- (IBAction)cancel:(id)sender
{
[self.list cancelEdit];
[self close];
}
- (IBAction)save:(id)sender
{
[self.list endEdit];
[self close];
}
The category implements beginEdit
, endEdit
and cancelEdit
which is intended to handle the NSUndoManager stuff. In the code below, useUndo
is a constant that I set to NO or YES to see the impact of using NSUndoManager.
- (void)beginEdit
{
if (useUndo)
{
NSUndoManager *undoManager = [[NSUndoManager alloc] init];
self.managedObjectContext.undoManager = undoManager;
[undoManager beginUndoGrouping];
}
}
- (void)endEdit
{
[self.managedObjectContext save:nil];
if (useUndo)
{
NSUndoManager *undoManager = self.managedObjectContext.undoManager;
[undoManager endUndoGrouping];
self.managedObjectContext.undoManager = nil;
}
}
- (void)cancelEdit
{
if (useUndo)
{
NSUndoManager *undoManager = self.managedObjectContext.undoManager;
[undoManager endUndoGrouping];
[undoManager undo];
}
}
I can see the Core Data debug messages showing it is committing the changes if I save an object and click the Home button when useUndo = NO
. However, with useUndo = YES
, it does not auto-save when I click on the Home button. I have waited a couple of minutes, and it still doesn't autosave. Is there some way I can force an auto-save?
Can anybody explain why using undoManager causes this change in behaviour?
I suspect either I am going about this the wrong way, or have some simple problem in the code. Any help would be appreciated.