objective-c - 如何取消正在进行的撤消/重做操作?

标签 objective-c cocoa undo

我已经对 Cocoa 进行了几个月的修补,并且正在尝试向我正在编写的一个严格用于学习目的的 Cocoa 应用程序添加撤消/重做支持,该应用程序允许您调整 iTunes 轨道元数据。多亏了 NSUndoManager 的 prepareWithInvocationTarget: 方法,我有了基础知识 — 例如,您可以撤消/重做对所选轨道的播放次数和上次播放日期的更改。 (我正在使用 appscript-objc 来获取/设置 iTunes 轨道数据。)

然而,由于更新大量 iTunes 轨道可能需要一些时间,我想让用户能够在正在进行的过程中取消撤消/重做操作,但我没有看到明显的机制用 NSUndoManager 完成这个。我该怎么做呢?

编辑:
澄清一下,再考虑一下,我想我真正想要的是一种操纵撤消/重做堆栈的方法,这样我就可以避免 Rob Napier 在他的回答中提到的“不一致状态”。

因此,为了响应未进行任何更改而失败的撤消操作(例如,在调用撤消之前,用户打开了 iTunes 的“偏好设置”窗口,这阻止了 Apple Events),撤消操作可以保留在顶部撤消堆栈,重做堆栈将保持不变。如果操作在中途被取消或失败,那么我想将一个操作推到重做堆栈上,该操作会反转经过的更改(如果有的话),并在撤消堆栈顶部执行一个应用未应用更改的操作成功。我认为在撤消和重做堆栈之间有效地拆分操作可能会引起用户混淆,但这似乎是处理该问题的最宽容的方式。

我怀疑对此的答案可能是“编写你自己该死的撤消管理器”、“你的撤消操作不应该失败”或“你不必要地过度复杂化”之一,但我很好奇。 :)

最佳答案

这是您的代码的问题,而不是 NSUndoManager 的问题。无论您请求 NSUndoManager 调用什么方法,都需要具有中断功能。这与最初执行时取消操作没有什么不同(事实上,它应该尽可能是相同的代码)。有两种常见的方法可以实现这一点,使用或不使用线程。

在线程的情况下,您在后台线程上运行撤消操作,并在每个循环中检查一个 BOOL,例如 self.shouldContinue。如果它曾被设置为 false(通常由其他线程设置),那么您将停止。

在没有线程的情况下实现这一点的类似方法是这样的:

- (void)doOperation
{
    if ([self.thingsToDo count] == 0 || ! self.shouldContinue)
    {
        return;
    }

    id thing = [self.thingsToDo lastObject];
    [self.thingsToDo removeLastObject];

    // Do something with thing

    [self performSelector:@selector(doOperation) withObject: nil afterDelay:0];
}

这里的一个主要问题是此取消将使您的撤消堆栈处于不确定状态。由你来处理。同样,这与您创建撤消项时的初始情况没有什么不同。不管你如何处理中断,你应该如何在撤消期间处理中断。它们通常不是不同类型的操作。

关于objective-c - 如何取消正在进行的撤消/重做操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1634709/

相关文章:

java - 为什么 JavaFX 不包含撤消功能

javascript - 带有 javascript 代码的 iPhone 应用程序和 uiwebview 我可以访问变量吗?

ios - 不确定为什么 NSUserdefaults 不保存结果?

ios - Objective-C - 左下角的文本基线

cocoa - 标签对齐

javascript - 禁用 Chrome 的文本输入撤消/重做 (CTRL+Z/CTRL+Y)

ios - iOS 中的手机号码验证问题

cocoa - NSTableView保证数据显示

objective-c - 如何从我的 Cocoa 应用程序在终端中运行命令?

tinymce - tinyMCE 撤消如何工作?