简体   繁体   English

使用NSUndoManager,如何使用Swift闭包注册撤消

[英]Using NSUndoManager, how to register undos using Swift closures

I am trying to grok how to use NSLayoutManager using Swift closures. 我试图了解如何使用Swift闭包使用NSLayoutManager I can successfully register an undo as follows: 我可以成功注册undo ,如下所示:

doThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
    undoThing();
}
undoManager?.setActionName("do thing")

Of course I need to support redo which amounts to an undo of an undo. 当然我需要支持redo ,这相当于撤消撤消。 I can do that: 我能做到:

doThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
    undoThing();

    undoManager?.registerUndoWithTarget(self, handler: { _ in
        doThing();
    }
    undoManager?.setActionName("do thing")
}
undoManager?.setActionName("do thing")

But now I need to support an undo of the redo... hmmm.... ok: 但现在我需要支持重做的撤消...嗯....好的:

doThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
    undoThing();

    undoManager?.registerUndoWithTarget(self, handler: { _ in
        doThing();

        undoManager?.registerUndoWithTarget(self, handler: { _ in
             undoThing();
        }
        undoManager?.setActionName("do thing")
    }
    undoManager?.setActionName("do thing")
}
undoManager?.setActionName("do thing")

As you can see its "turtles all the way down." 正如你可以看到它的“乌龟一直向下”。 How do I escape from this madness? 我如何摆脱这种疯狂? ie, in all the example code I can find, folks use the selector version of the code to register a method that can undo itself -- this is not obviously doable with the closure method I am using... How does one use the closure version and get unlimited undo/redo? 也就是说,在我能找到的所有示例代码中,人们使用代码的选择器版本来注册一个可以撤消自身的方法 - 这对于我正在使用的闭包方法显然不可行...如何使用闭包版本并获得无限制的撤消/重做?

What you're looking for is mutual recursion. 您正在寻找的是相互递归。 You need two functions, each of which registers a call to the other. 您需要两个函数,每个函数都会调用另一个函数。 Here are a couple of different ways to structure it: 以下是构建它的几种不同方法:

  1. In doThing() , register the undo action to call undoThing() . doThing() ,注册撤消操作以调用undoThing() In undoThing , register the undo action to call doThing() . undoThing ,注册撤消操作以调用doThing() That is: 那是:

     @IBAction func doThing() { undoManager?.registerUndoWithTarget(self, handler: { me in me.undoThing() }) undoManager?.setActionName("Thing") // do the thing here } @IBAction func undoThing() { undoManager?.registerUndoWithTarget(self, handler: { me in me.doThing() }) undoManager?.setActionName("Thing") // undo the thing here } 

Note that you should not refer to self in the closure unless you capture it with weak , because capturing it strongly (the default) may create a retain cycle. 请注意,你应该是指self的封闭,除非你抓住它weak ,因为它捕捉强(默认值)可以创建一个保留周期。 Since you're passing self to the undo manager as target , it's already keeping a weak reference for you and passing it (strongly) to the undo block, so you might as well use that and not reference self at all in the undo block. 由于您将self作为target传递给撤消管理器,因此它已经为您保留了弱引用并将其(强烈地)传递给撤消块,因此您可以使用它而不是在撤消块中引用self

  1. Wrap the calls to doThing() and undoThing() in separate functions that handle undo registration, and connect user actions to those new functions: doThing()undoThing()的调用doThing()在处理撤销注册的单独函数中,并将用户操作连接到这些新函数:

     private func doThing() { // do the thing here } private func undoThing() { // undo the thing here } @IBAction func undoablyDoThing() { undoManager?.registerUndoWithTarget(self, handler: { me in me.redoablyUndoThing() }) undoManager?.setActionName("Thing") doThing() } @IBAction func redoablyUndoThing() { undoManager?.registerUndoWithTarget(self, handler: { me in me.undoablyDoThing() }) undoManager?.setActionName("Thing") undoThing() } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM