Undo/Redo 从未启用的菜单项
Undo/Redo Menu Items Never Enabled
我有一个核心数据应用程序,其中 NSTableView 绑定到 NSArrayController。我使用数组控制器管理添加和删除对象。我正在尝试添加 undo/redo 支持,以便当有人使用菜单项从 table 视图中删除对象时,他们可以撤消删除。
我的删除方法是:
- (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"];
}
删除对象可以正常工作,但撤消则不行。 Command-Z 菜单项永远不会启用。我设置了一个临时菜单项和操作来测试 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];
}
使用这个 IBAction 我可以撤消(嗯,有点,它添加了两次对象,所以很明显这里还有更多错误),但我只能撤消一次。如果我删除另一个对象 canUndo returns 0,而 stupidUndoRemoveHost 什么都不做。
我知道我不理解这里的内容。我在这里阅读的帖子多得数不过来,还有几篇博文和 Apple documentation。我以前做过这个,但那是十年前的事了,所以我的技术有点生疏了。非常感谢任何正确方向的帮助或指示。
更新:这里是 addBookmarkObject 方法:
- (void)addBookmarkObject: (NSManagedObject *)object
{
[bookmarksController addObject:object];
}
这是来自 AppDelegate 的 windowWillReturnUndoManager
:
- (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:
每次 Appkit 想要注册一个撤消操作和想要 enable/disable 撤消菜单项时被调用。如果 windowWillReturnUndoManager:
returns 一个新的撤消管理器,则撤消堆栈为空并且撤消菜单项被禁用。
Core Data 会在删除对象时注册一个撤消操作,removeHost:
不应该注册一个额外的撤消操作。
- (IBAction)removeHost:(id)sender
{
[bookmarksController remove:sender];
[undoManager setActionName:@"Bookmark Delete"];
}
带有 Core Data 模板的 Xcode macOS Cocoa 应用程序存在一些缺陷。
NSWindowDelegate
方法 windowWillReturnUndoManager:
未被调用,因为在 xib 中,window 的委托未连接到应用程序委托。修复:将 window 的委托连接到委托。
self.persistentContainer.viewContext.undoManager
是 nil
。修复:创建持久容器时创建一次撤消管理器。
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
@synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"TestCDUndo"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
…
abort();
}
self->_persistentContainer.viewContext.undoManager = [[NSUndoManager alloc] init];
}];
}
}
return _persistentContainer;
}
我有一个核心数据应用程序,其中 NSTableView 绑定到 NSArrayController。我使用数组控制器管理添加和删除对象。我正在尝试添加 undo/redo 支持,以便当有人使用菜单项从 table 视图中删除对象时,他们可以撤消删除。
我的删除方法是:
- (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"];
}
删除对象可以正常工作,但撤消则不行。 Command-Z 菜单项永远不会启用。我设置了一个临时菜单项和操作来测试 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];
}
使用这个 IBAction 我可以撤消(嗯,有点,它添加了两次对象,所以很明显这里还有更多错误),但我只能撤消一次。如果我删除另一个对象 canUndo returns 0,而 stupidUndoRemoveHost 什么都不做。
我知道我不理解这里的内容。我在这里阅读的帖子多得数不过来,还有几篇博文和 Apple documentation。我以前做过这个,但那是十年前的事了,所以我的技术有点生疏了。非常感谢任何正确方向的帮助或指示。
更新:这里是 addBookmarkObject 方法:
- (void)addBookmarkObject: (NSManagedObject *)object
{
[bookmarksController addObject:object];
}
这是来自 AppDelegate 的 windowWillReturnUndoManager
:
- (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:
每次 Appkit 想要注册一个撤消操作和想要 enable/disable 撤消菜单项时被调用。如果 windowWillReturnUndoManager:
returns 一个新的撤消管理器,则撤消堆栈为空并且撤消菜单项被禁用。
Core Data 会在删除对象时注册一个撤消操作,removeHost:
不应该注册一个额外的撤消操作。
- (IBAction)removeHost:(id)sender
{
[bookmarksController remove:sender];
[undoManager setActionName:@"Bookmark Delete"];
}
带有 Core Data 模板的 Xcode macOS Cocoa 应用程序存在一些缺陷。
NSWindowDelegate
方法 windowWillReturnUndoManager:
未被调用,因为在 xib 中,window 的委托未连接到应用程序委托。修复:将 window 的委托连接到委托。
self.persistentContainer.viewContext.undoManager
是 nil
。修复:创建持久容器时创建一次撤消管理器。
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
@synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"TestCDUndo"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
…
abort();
}
self->_persistentContainer.viewContext.undoManager = [[NSUndoManager alloc] init];
}];
}
}
return _persistentContainer;
}