Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift中基于调用的撤销管理器_Swift_Cocoa_Nsundomanager - Fatal编程技术网

Swift中基于调用的撤销管理器

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:

我很难在Swift中采用更复杂的基于调用的方法来撤销注册(基于NSHipster文章。Apple的文档中仍然有Objective-C中的所有示例代码,调用设置的语义非常不同)

我的
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
。出于某种原因,我错过了您链接的问题/答案;谢谢。