使用 NSUndoManager,如何使用 Swift 闭包注册撤销
Using NSUndoManager, how to register undos using Swift closures
我正在尝试了解如何使用 Swift 闭包来使用 NSLayoutManager
。我可以成功注册一个 undo
如下:
doThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
undoThing();
}
undoManager?.setActionName("do thing")
当然我需要支持redo
,这相当于撤消了撤消。我可以做到:
doThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
undoThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
doThing();
}
undoManager?.setActionName("do thing")
}
undoManager?.setActionName("do thing")
但现在我需要支持撤销重做...嗯...好的:
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")
如您所见 "turtles all the way down." 我该如何摆脱这种疯狂?即,在我能找到的所有示例代码中,人们使用代码的选择器版本来注册一个可以撤消自身的方法——这显然不适用于我正在使用的闭包方法……如何使用闭包版本并获得无限 undo/redo?
你要找的是相互递归。您需要两个函数,每个函数都注册对另一个的调用。这里有几种不同的结构方式:
在doThing()
中,注册撤消操作以调用undoThing()
。在 undoThing
中,注册撤消操作以调用 doThing()
。即:
@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
}
请注意,您应该不在闭包中引用self
,除非您使用weak
捕获它,因为强烈捕获它(默认)可能创建一个保留周期。由于您将 self
作为 target
传递给撤消管理器,它已经为您保留了弱引用并将其(强)传递给撤消块,因此您不妨使用它而不是引用self
完全在撤消块中。
将对 doThing()
和 undoThing()
的调用包装在处理撤消注册的单独函数中,并将用户操作连接到这些新函数:
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()
}
我正在尝试了解如何使用 Swift 闭包来使用 NSLayoutManager
。我可以成功注册一个 undo
如下:
doThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
undoThing();
}
undoManager?.setActionName("do thing")
当然我需要支持redo
,这相当于撤消了撤消。我可以做到:
doThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
undoThing();
undoManager?.registerUndoWithTarget(self, handler: { _ in
doThing();
}
undoManager?.setActionName("do thing")
}
undoManager?.setActionName("do thing")
但现在我需要支持撤销重做...嗯...好的:
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")
如您所见 "turtles all the way down." 我该如何摆脱这种疯狂?即,在我能找到的所有示例代码中,人们使用代码的选择器版本来注册一个可以撤消自身的方法——这显然不适用于我正在使用的闭包方法……如何使用闭包版本并获得无限 undo/redo?
你要找的是相互递归。您需要两个函数,每个函数都注册对另一个的调用。这里有几种不同的结构方式:
在
doThing()
中,注册撤消操作以调用undoThing()
。在undoThing
中,注册撤消操作以调用doThing()
。即:@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 }
请注意,您应该不在闭包中引用self
,除非您使用weak
捕获它,因为强烈捕获它(默认)可能创建一个保留周期。由于您将 self
作为 target
传递给撤消管理器,它已经为您保留了弱引用并将其(强)传递给撤消块,因此您不妨使用它而不是引用self
完全在撤消块中。
将对
doThing()
和undoThing()
的调用包装在处理撤消注册的单独函数中,并将用户操作连接到这些新函数: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() }