Search code examples
iosnsundomanagernsinvocation

How to force NSUndoManager prepareWithInvocationTarget to retain it's arguments?


NSUndoManager method prepareWithInvocationTarget does not retain arguments. There is no links to this in Apple docs, but I've checked with profiler, and I'm pretty sure - it does not. This means if you are going to delete an object and be prepared for undo - you should retain it yourself (like assign it to some trash array and remove the original link). Those kind of fake removes creates a lot of unnecessary fuss, especially when you need to get rid of the old undos.

However, NSInvocation can retain arguments by calling retainArguments method. Since NSUndoManager uses NSInvocation for prepareWithInvocationTarget it might be the way to pass retainArguments to NSUndoManager.

The question is - how to do it?


Solution

  • It's right there in the Undo Architecture guide:

    An NSUndoManager object does not retain the targets of undo operations. The client—the object performing undo operations—typically owns the undo manager, so if the undo manager in turn retained its target this would frequently create a retain cycle.

    So No, it doesn't - for the reasons given in the docs.

    You'll have to manage live cycles on your own. How entirely depends on and is completely specific to your apps model.. I guess the general question boils down to:

    How do we know when the NSUndoManager will 'pop' an action from the undo stack (so we can safely delete our context data we're keeping around for the undo operation).

    Unfortunately there's no (documented) notification in the NSUndoManager Class Reference that's sent e.g. when removeAllActionsWithTarget: is invoked on an undo manager instance.

    Almost seems like there's no real alternative to keep that additional information around forever (or manually limit the levels of undo and adjust the storage for the undo context data accordingly).