我有两个答案给你。第一个是处理这个问题的常见方法:
当您点击取消按钮时调用撤销操作,让NSUndoManager为您回滚所有更改。
请参见:
http://www.cimgf.com/2008/04/30/cocoa-tutorial-wiring-undo-management-into-core-data/
http://www.mac-developer-network.com/columns/coredata/coredatafeb09/
以了解此方法的示例。他们正在讨论表格,但它应该适用于任何可取消的内容。
这种方法的问题在于它会留下不一致的重做堆栈。您可以通过调用removeAllActionsWithTarget:来从NSUndoManager中驱逐目标来解决这个问题:
第二个解决方案要复杂得多,但我实际上正在使用它,并且它有效。我正在使用Java中的移植版本,因此如果示例不是objective-c,则请原谅,但我仍将尝试传达概念。
我为该操作创建了一个新的撤销管理器,并将其设置为“活动”(我想这意味着在Cocoa中将其设置为您的控制器)。我保留对原始管理器的引用,以便在完成后将事物恢复到正常状态。
如果用户点击取消按钮,则可以在活动撤销管理器上调用undo,然后释放它并将原始撤销管理器恢复到先前的位置。原始管理器不会有任何未决的撤销或重做操作,除了最初存在的那些操作。
如果该操作成功,则需要进行一些棘手的处理。此时,您需要使用registerUndoWithTarget:selector:object:来注册。下面是需要发生的一些伪代码:
invoke(boolean undo) {
oldUndoManager = currentUndoManager
setCurrentUndoManager(temporaryUndoManager)
if (undo)
temporaryUndoManager.undo()
oldUndoManager.registerUndo(temporaryUndoManager,
"invoke", false)
else
temporaryUndoManager.redo()
oldUndoManager.registerUndo(temporaryUndoManager,
"invoke", true)
setCurrentUndoManager(oldUndoManager)
}
这将允许您的原始(旧)撤销管理器基本上在新的(临时的)撤销管理器上调用撤销/重做,并响应地设置相应的撤销/重做操作。 这比第一个更复杂,但确实帮助我做到了我想做的事情。
我的理念是只有完成的操作才应该进入撤销管理器。 取消的操作是一种实际上从未存在过的操作。 我不知道任何苹果文档中有这样的说法,这只是我的个人意见。