Регистрация операций отмены

Эта статья описывает эти два способа, которыми Вы регистрируете работу отмены в менеджере по отмене.

Обзор

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

В большинстве приложений единственный экземпляр NSUndoManager принадлежит объекту, содержащему или управляющему другими объектами. Это особенно имеет место с настольными основанными на документе приложениями, где каждый NSDocument объект ответственен за всю отмену и операции восстановления для документа. Объект, такой как это часто вызывают клиентом менеджера по отмене. Каждый объект клиента имеет свое собственное NSUndoManager. Клиент требует исключительного права изменить его невыполнимые объекты так, чтобы оно могло записать операции отмены для всех изменений. В конкретном случае документов эта схема сохраняет каждую пару стеков отмены и стеков повторного выполнения отдельной так, чтобы, когда отмена выполняется, это применилось к фокальному документу в приложении (обычно то, выведенное на экран в ключевом окне). Это также уменьшает отдельные объекты в документе от необходимости знать идентификационные данные их менеджера по отмене или от необходимости отследить изменения в себе.

Однако изменяющийся объект может иметь своего собственного менеджера по отмене и выполнить его собственную отмену и восстановить операции. Например, у Вас могло быть пользовательское представление, что изображения дисплеев перетащили в него; с каждым успешная работа перетаскивания это регистрирует новую группу отмены. Если представление тогда выбрано (т.е. сделал первого респондента), и примененная команда Undo, ранее выведенное на экран изображение будет восстановлено.

Многие следующие примеры кода регистрируют тот же метод для отмены и восстанавливают операции. Несмотря на то, что тот подход удобен, когда отмена и восстановление переключают простое значение данных между двумя состояниями, Вы не должны регистрировать тот же метод для операций восстановления и отмены. Когда то, что отменяется и восстанавливается, более сложно — например, вставка и удаление объектов в массиве — Вы могли вызвать пару методов в чередовании, то, знающее, как создать состояние и другого, который знает, как вскрыть противоречия в нем. При регистрации селектора как действия отмены это заставляет метод, идентифицированный тем селектором быть вызванным, когда пользователь запрашивает это, что произошло в данном контексте быть отмененным. Метод не должен быть тем же самым, в котором произошла регистрация. И сам метод мог зарегистрировать свой собственный селектор отмены. Важный момент - то, что, при регистрации отмены и операций восстановления, могут варьироваться и состояние данных и селектор.

Простая отмена

Для записи простой работы отмены Вы должны только вызвать registerUndoWithTarget:selector:object:, давая объект, который будет отправлен селектор работы отмены, селектор для вызова, и параметр для передачи с тем сообщением. Целевой объект может не быть фактическим объектом, состояние которого изменяется; вместо этого, это может быть объект клиента, документ или контейнер, содержащий много невыполнимых объектов. Параметром является объект, получающий состояние объекта, прежде чем изменение будет внесено, как проиллюстрировано в следующем примере:

- (void)setMyObjectTitle:(NSString *)newTitle {
 
    NSString *currentTitle = [myObject title];
    if (newTitle != currentTitle) {
        [undoManager registerUndoWithTarget:self
                selector:@selector(setMyObjectTitle:)
                object:currentTitle];
        [undoManager setActionName:NSLocalizedString(@"Title Change", @"title undo")];
        [myObject setTitle:newTitle];
    }
}

В работе отмены, setMyObjectTitle: вызывается с предыдущим значением. Заметьте, что это снова вызовет registerUndoWithTarget:selector:object: метод — в этом случае с «новым» значением myObjectзаголовок. Так как менеджер по отмене находится в процессе отмены, он зарегистрирован как работа восстановления.

Основанная на вызове отмена

Для других изменений, включающих определенные методы или параметры, которые не являются объектами, можно использовать основанную на вызове отмену, записывающую фактическое сообщение для возвращения состояния целевого объекта. Как с простой отменой, Вы записываете сообщение, возвращающееся объект к его состоянию перед изменением. Однако в этом случае Вы делаете так путем отправки сообщения непосредственно в менеджера по отмене после подготовки его со специальным сообщением (prepareWithInvocationTarget:) отметить цель, как в этом примере:

- (void)setMyObjectWidth:(CGFloat)newWidth height:(CGFloat)newHeight{
 
    float currentWidth = [myObject size].width;
    float currentHeight = [myObject size].height;
    if ((newWidth != currentWidth) || (newHeight != currentHeight)) {
        [[undoManager prepareWithInvocationTarget:self]
                setMyObjectWidth:currentWidth height:currentHeight];
        [undoManager setActionName:NSLocalizedString(@"Size Change", @"size undo")];
        [myObject setSize:NSMakeSize(newWidth, newHeight)];
    }
}

prepareWithInvocationTarget: метод записывает параметр как цель работы отмены, собирающейся быть установленным. После этого Вы отправляете сообщение, возвращающееся состояние цели — в этом случае, setMyObjectWidth:height:. Поскольку NSUndoManager не реагирует на этот метод, forwardInvocation: вызывается, который NSUndoManager реализации для записи NSInvocation объект, содержащий цель, селектор и все параметры. Выполнение отмены таким образом приводит к сам отправляемый a setMyObjectWidth:height: сообщение с исходными значениями.