У меня проблема с UndoManager
, которая может быть ошибкой iPadOS, но также может быть моей ошибкой.
У меня есть простое тестовое приложение. Одна кнопка выполняет действие, которое увеличивает int на 1 и регистрирует отмену в системе UndoManager
. Другая кнопка вручную вызывает undoManager.undo()
, которая отменяет последнее действие до тех пор, пока не останется больше никаких действий в стеке отмены. И в целом приложение является первым респондентом системы, поэтому нажатие CMD+Z
также должно инициировать вызов undoManager undo()
один раз за CMD + Z, нажмите .
Вот некоторый код.
Подкласс UIHostingController, который позволяет стать первым респондентом:
class FirstResponderHostingController<Content: View>: UIHostingController<Content> {
override var canBecomeFirstResponder: Bool { true }
}
SceneDelegate, где я передаю в диспетчере отмены системы:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let model = MyObject(undoManager: window.undoManager)
let contentView = ContentView(model: model)
window.rootViewController = FirstResponderHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
//...
}
И мое представление SwiftUI и связанные с ним модель:
class MyObject: ObservableObject {
var undoManager: UndoManager?
var state: Int = 0
init(undoManager: UndoManager? = nil) {
self.undoManager = undoManager
}
func registerAction() {
state += 1
undoManager?.registerUndo(withTarget: self, selector: #selector(performUndo), object: nil)
print("registered action - state is \(state)")
}
@objc func performUndo() {
state -= 1
print("performUndo called - state is \(state)")
}
func undo() {
print("undo() called")
undoManager?.undo()
}
}
struct ContentView: View {
@ObservedObject var model: MyObject
var body: some View {
VStack(spacing: 16) {
Button(action: {
self.model.registerAction()
}) {
Text("Register an Action")
}
Button(action: {
self.model.undo()
}) {
Text("Manual Undo (Not from Keyboard)")
}
}
}
}
Так, например, если я дважды коснусь «Зарегистрировать действие», а затем трижды «Отмена вручную», результат будет таким, как я ожидаю - состояние было увеличено в два раза, а затем уменьшено в два раза, и последняя отмена () ничего не делает, потому что стек отмены пуст:
registered action - state is 1
registered action - state is 2
undo() called
performUndo called - state is 1
undo() called
performUndo called - state is 0
undo() called
Но если я дважды нажму "Зарегистрировать действие", а затем нажму CMD+Z
на клавиатуре iPad, я ожидаю, что состояние увеличиваться в два раза и уменьшаться только один раз, с одним вызовом performUndo
, но вместо этого performUndo
по-прежнему вызывается дважды:
registered action - state is 1
registered action - state is 2
performUndo called - state is 1
performUndo called - state is 0
Я как-то неправильно использую систему UndoManager или это ошибка?
Обновление: Выше приведено с Xcode 11.3.1 и iPadOS 13.3. Используя последние версии Xcode 11.4 beta 2 и iPadOS 13.4 beta 2, двойная отмена больше не происходит. Кажется исправлено!