Пункты меню отмены / повтора никогда не включены - PullRequest
0 голосов
/ 20 января 2020

У меня есть основное приложение данных с NSTableView, привязанным к NSArrayController. Я управляю добавлением и удалением объектов с помощью контроллера массива. Я пытаюсь добавить поддержку отмены / повтора, чтобы, когда человек удаляет объект из табличного представления, используя пункт меню, он мог отменить удаление.

Мой метод удаления:

- (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 возвращает 0, а stupidUndoRemoveHost ничего не делает.

Я знаю, что здесь что-то не понимаю. Я прочитал здесь больше постов, чем могу сосчитать, несколько постов в блоге и документацию Apple . Я делал это раньше, но это было как десять лет go, так что мои навыки немного ржавые. Любая помощь или указатели в правильном направлении с благодарностью.

Обновление: вот метод addBookmarkObject:

- (void)addBookmarkObject: (NSManagedObject *)object
{
    [bookmarksController addObject:object];
}

А вот windowWillReturnUndoManager из 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;
}

1 Ответ

1 голос
/ 22 января 2020

windowWillReturnUndoManager: вызывается каждый раз, когда Appkit хочет зарегистрировать операцию отмены и когда он хочет включить / отключить пункт меню Undo. Если windowWillReturnUndoManager: возвращает новый менеджер отмены, то стек отмены пуст и элемент меню отмены отключен.

Базовые данные будут регистрировать операцию отмены при удалении объекта, removeHost: не должен регистрировать дополнительная операция отмены.

- (IBAction)removeHost:(id)sender
{
    [bookmarksController remove:sender];
    [undoManager setActionName:@"Bookmark Delete"];
}

Приложение Xcode macOS Cocoa с шаблоном Core Data имеет некоторый fl aws.

NSWindowDelegate метод windowWillReturnUndoManager: не вызывается, поскольку в xib делегат окна не связан с делегатом приложения. Исправлено: подключить делегата окна к Делегату.

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;
}
...