I have a core data application with an NSTableView bound to an NSArrayController. I manage adding and removing objects using the array controller. I'm trying to add undo/redo support so when a person deletes an object from the table view, using a menu item, they can undo the delete.
My delete method is:
- (IBAction)removeHost:(id)sender
{
NSInteger row = [bookmarkList selectedRow];
// Get the object so we can get to the attributes of the host
NSArray *a = [bookmarksController arrangedObjects];
NSManagedObject *object = [a objectAtIndex:row];
if (!object) return;
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSUndoManager *undoManager = [managedObjectContext undoManager];
if (managedObjectContext.undoManager == nil)
{
NSLog(@"No undo manager in app controller!");
} else {
NSLog(@"We've got an undo manager in app controller!");
}
[undoManager registerUndoWithTarget:self selector:@selector(addBookmarkObject:) object:object];
[bookmarksController removeObject:object];
[undoManager setActionName:@"Bookmark Delete"];
}
Deleting the object works fine, but undo does not. The Command-Z menu item is never enabled. I setup a temporary menu item and action to test the undoManager,
- (IBAction)stupidUndoRemoveHost:(id)sender
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSUndoManager *undoer = [managedObjectContext undoManager];
NSLog(@"canUndo? %hhd", [undoer canUndo]);
NSLog(@"canRedo? %hhd", [undoer canRedo]);
NSLog(@"isUndoRegistrationEnabled? %hhd", [undoer isUndoRegistrationEnabled]);
NSLog(@"undoMenuItemTitle = %@", [undoer undoMenuItemTitle]);
NSLog(@"redoMenuItemTitle = %@", [undoer redoMenuItemTitle]);
[undoer undo];
}
Using this IBAction I can do the undo (well, sort of, it adds the object twice so clearly there's still more wrong here), but I can only do it once. If I delete another object canUndo returns 0, and stupidUndoRemoveHost does nothing.
I know I'm not understanding something here. I've read through more posts here than I can count, several blog posts, and the Apple documentation. I've done this before, but it was like ten years ago, so my skills are a bit rusty. Any help or pointers in the right direction are greatly appreciated.
Update: here is the addBookmarkObject method:
- (void)addBookmarkObject: (NSManagedObject *)object
{
[bookmarksController addObject:object];
}
And here is windowWillReturnUndoManager
from the AppDelegate:
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
// Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application.
NSUndoManager *undoManager = [[NSUndoManager alloc] init];
self.persistentContainer.viewContext.undoManager = undoManager;
if (self.persistentContainer.viewContext.undoManager == nil)
{
NSLog(@"No undo manager!");
} else {
NSLog(@"We've got an undo manager!");
}
return self.persistentContainer.viewContext.undoManager;
}
windowWillReturnUndoManager:
? Is this a document based app? – WillekewindowWillReturnUndoManager
there's no undo manager. Logs in my App Controller'sstupidUndoRemoveHost
show there's no undo manager, same in the delegate. – Jon Buys