Nsundomanager Casting Nsundomanagerproxy Crash in Swift Code

NSUndoManager casting NSUndoManagerProxy crash in Swift code

I am so much astonished that I hear your first code works on macOS 10.12. The method prepare(withInvocationTarget:) has been a this-hardly-works-in-Swift thing. Not only the returned proxy object is not the instance of the original class, but neither the object is not a descendent of NSObject (at lease in some former OS Xs).

Anyway, this is one thing worth trying:

let lInvocationTarget = lUndoManager.prepare(withInvocationTarget: self)
_ = (lInvocationTarget as AnyObject).myMethod(self.opacity, undoManager: lUndoManager)

Using NSUndoManager and .prepare(withInvocationTarget:) in Swift 3

prepareWithInvocationTarget(_:)(or prepare(withInvocationTarget:) in Swift 3) creates a hidden proxy object, with which Swift 3 runtime cannot work well.

(You may call that a bug, and send a bug report.)

To achieve your purpose, can't you use registerUndo(withTarget:handler:)?

undoManager?.registerUndo(withTarget: self) {targetSelf in
targetSelf.undo(data, moreData: moreData)
}

Invocation-based Undo Manager in Swift

I think the basic confusion is that prepare(withInvocationTarget:) returns a proxy object (that happens to be the undo manager itself, but that's an implementation detail). The idea is that you send this proxy object the same message(s) you send to undo the action, but instead of executing them (because it's not the actual object), it internally captures those invocations and saves them for later.

So your code should really start out something like this:

let selfProxy: Any = undoManager?.prepare(withInvocationTarget: self)

This works great in Objective-C because the "catchall" type (id) has very lax type checking. But the equivalent Any class in Swift is much more stringent and does not lend itself to the same technique, if at all.

See Using NSUndoManager and .prepare(withInvocationTarget:) in Swift 3



Related Topics



Leave a reply



Submit