Используя NSUndoManager, как зарегистрировать отмены с помощью замыканий Swift
Я пытаюсь понять, как использовать NSLayoutManager
используя закрытие Swift. Я могу успешно зарегистрировать 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")
Как видите, "черепахи внизу". Как мне избежать этого безумия? то есть, во всем примере кода, который я могу найти, люди используют версию кода селектора, чтобы зарегистрировать метод, который может отменить сам - это явно не выполнимо с методом закрытия, который я использую... Как можно использовать замыкание версия и получить неограниченное отменить / повторить?
1 ответ
То, что вы ищете, это взаимная рекурсия. Вам нужны две функции, каждая из которых регистрирует вызов другой. Вот несколько способов структурировать его:
В
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() }