Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I have two answers for you. The first is the common way to handle this:</p> <p>Call undo when you hit the cancel button and let NSUndoManager roll back all the changes for you.</p> <p>See: <a href="http://www.cimgf.com/2008/04/30/cocoa-tutorial-wiring-undo-management-into-core-data/" rel="nofollow noreferrer">http://www.cimgf.com/2008/04/30/cocoa-tutorial-wiring-undo-management-into-core-data/</a> <a href="http://www.mac-developer-network.com/columns/coredata/coredatafeb09/" rel="nofollow noreferrer">http://www.mac-developer-network.com/columns/coredata/coredatafeb09/</a> for examples of this method. They are discussing sheets but it should apply with anything that is cancelable.</p> <p>The problem with this method is that it will leave an inconsistent redo stack. You may be able to solve this by evicting the target from NSUndoManager with a call to removeAllActionsWithTarget:</p> <p>The second solution is a lot more complicated but I actually use it and it works. I am using a ported version in Java so forgive if the example is not in objective-c but I will try to get the concept across anyways.</p> <p>I create a new undo manager strictly for the operation and set it so it is the "active" one (I think that means setting it on your controller in Cocoa). I keep a reference to the original one so I can set things back to normal when I am done.</p> <p>If they hit the cancel button you can call undo on your active undo manager, release it and set the original undo manager back to where it was before. The original will not have any undo or redo actions pending other than the ones that were originally there.</p> <p>If the operation succeeds then it is a bit tricky. At this point you need to registerUndoWithTarget:selector:object:. Here is a little pseudo code of what needs to happen:</p> <pre><code>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) } </code></pre> <p>This will allow your original (old) undo manager to basically call undo/redo on your new (temporary) one and set up the corresponding undo/redo opposite in response. This is a lot more complicated than the first one, but really has helped me to do what I wanted to do.</p> <p>My philosophy is that only a completed operation should go to the undo manager. A cancelled operation is a operation that for all practical purposes never existed. You won't find that in any Apple documentation I know of though, just my opinion.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload