Question

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.

Was it helpful?

Solution

I'm not sure if it's correct but other answers on stackoverflow have mentioned that an NSUndoManager clears the undo stack when the context saves. That means that using an undo manager with auto-save would at most be useful for a couple of seconds (whatever the auto-save interval is). There might be a connection there, I'm trying to find out more...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top