Swift中基于调用的撤销管理器
我很难在Swift中采用更复杂的基于调用的方法来撤销注册(基于NSHipster文章。Apple的文档中仍然有Objective-C中的所有示例代码,调用设置的语义非常不同) 我的Swift中基于调用的撤销管理器,swift,cocoa,nsundomanager,Swift,Cocoa,Nsundomanager,我很难在Swift中采用更复杂的基于调用的方法来撤销注册(基于NSHipster文章。Apple的文档中仍然有Objective-C中的所有示例代码,调用设置的语义非常不同) 我的NSDocument子类Document具有对模型对象进行操作的以下方法,我希望使其可撤消: func rename(object: Any, to newName: String) { // This is basically a protocol that requires implementing:
NSDocument
子类Document
具有对模型对象进行操作的以下方法,我希望使其可撤消:
func rename(object: Any, to newName: String) {
// This is basically a protocol that requires implementing:
// var name: String { get set }
//
guard var namedObject = object as? EditorHierarchyDisplayable else {
return
}
// Register undo:
let undoController = undoManager?.prepare(withInvocationTarget: self) as? Document
undoController?.rename(object: namedObject, to: namedObject.name)
undoManager?.setActionName("Rename \(namedObject.localizedClassName)")
// Perform the change:
namedObject.name = newName
}
我发现上面的undoController
是nil
,因为对文档的强制转换失败。如果删除强制转换(并注释掉对undoController.rename(…
)的调用),prepare(withInvocationTarget:)
将返回以下对象:
(lldb) print undoController
(Any?) $R0 = some {
payload_data_0 = 0x00006080000398a0
payload_data_1 = 0x0000000000000000
payload_data_2 = 0x0000000000000000
instance_type = 0x000060800024f0d8
}
(lldb) print undoController.debugDescription
(String) $R1 = "Optional(NSUndoManagerProxy)"
(lldb)
我遗漏了什么?我认为基本的困惑在于prepare(withInvocationTarget:)
返回一个代理对象(该对象恰好是撤销管理器本身,但这是一个实现细节)。其思想是您将相同的消息发送给该代理对象您可以发送以撤消操作,但它不会执行这些操作(因为它不是实际的对象),而是在内部捕获这些调用并保存它们以供以后使用
所以你的代码应该是这样开始的:
let selfProxy: Any = undoManager?.prepare(withInvocationTarget: self)
这在Objective-C中非常有效,因为“catchall”类型(id)具有非常松散的类型检查。但是Swift中的等效Any
类更为严格,并且不适用于相同的技术(如果有的话)
请参阅prepare(withInvocationTarget:)
的文档说明“返回self”。self
是undoManager
。在NSHipster文章的底部,它说“本文使用Swift版本1.0”。是的,文档也是如此。但它将返回值转换为作为ViewController
(我假设这在我的情况下变成了Document
)。而且,在Swift 2+中,as
变成as?
将NSUndoManager
转换为Document
是错误的。Swift 1不在乎,但Swift 3拒绝这么做。那么,我如何调用我的Document
方法重命名(对象:to:)
在返回的代理上?Objective-C允许您向任何对象发送任何消息(至少在编译时),但Swift是强类型的…令我惊讶的是,我在回答中使用的方法被链接为“重复源”,即(目标为AnyObject)。methodOfMyTargetClass()
编译时没有错误或警告,即使target
是AnyObject
,而不是MyClass
。我认为Swift严格的类型系统不允许它编译。无论如何,我移到了更新的、基于闭包的注册表项下(带有target:handler:)
“这在Objective-C中非常有效,因为”catchall“类型(id)的类型检查非常松散。”-事实上,我过去在Objective-C代码中使用了NSUndoManager
。出于某种原因,我错过了您链接的问题/答案;谢谢。