我有一个NSDocument
子类,连接到NSArrayController
。作为参考,我正在尝试翻译 Cocoa Programming for Mac OS X Fourth Edition 的第9章中的示例。
似乎从我之前询问的this question,我需要使用基于对象的撤消NSUndoManager
。为了将两个值传递给被调用的方法,我将它们打包成一个带有两个实例变量的NSObject
子类。
当通过单击我的应用程序中的按钮调用从employees
数组插入和删除的KVO方法时,它们按预期工作。
但是,在撤消操作期间调用removeObjectFromEmployeesAtIndex
时,传入的index
超出边界(对于第一行,它似乎总是55
,然后索引在接下来的几行中增加到数千个。)
如何获取正确的索引来执行撤消操作?
class Document: NSDocument {
var employee_list: Array<Person> = []
var employees: Array<Person> {
get {
return self.employee_list
}
set {
if newValue == self.employee_list {
return
}
self.employee_list = newValue
}
}
func insertObject(person: Person, inEmployeesAtIndex index: Int) {
self.undoManager.registerUndoWithTarget(self, selector: Selector("removeObjectFromEmployeesAtIndex:"), object: index)
if (!self.undoManager.undoing) {
self.undoManager.setActionName("Add Person")
}
employees.insert(person, atIndex: index)
}
func removeObjectFromEmployeesAtIndex(index: Int) {
let person = self.employees[index]
let pair = PersonIndexPair(person: person, index: index)
self.undoManager.registerUndoWithTarget(self, selector: Selector("insertPersonIndexPair:"), object: pair)
if (!self.undoManager.undoing) {
self.undoManager.setActionName("Remove Person")
}
employees.removeAtIndex(index)
}
func insertPersonIndexPair(pair: PersonIndexPair) {
insertObject(pair.person, inEmployeesAtIndex: pair.index)
}
}
编辑:我通过传递一个字符串解决了这个问题,但这看起来很晦涩:
self.undoManager.registerUndoWithTarget(self, selector: Selector("removeObjectFromEmployeesAtStringIndex:"), object: String(index))
//...
func removeObjectFromEmployeesAtStringIndex(index: String) {
if let i = index.toInt() {
removeObjectFromEmployeesAtIndex(i)
}
}
答案 0 :(得分:0)
使用NSNumber而不是Int。
self.undoManager.registerUndoWithTarget(self, selector:Selector("removeObjectFromEmployeesAtStringIndex:"), object: NSNumber(integer: index))
//...
func removeObjectFromEmployeesAtStringIndex(index: NSNumber) {
removeObjectFromEmployeesAtIndex(index.integerValue)
}
答案 1 :(得分:0)
我现在正在阅读 Mac OS X的Cocoa编程。我将示例Object-C代码翻译成如下所示,只需将其附加到类Document:
func insertObject(p: Person, inEmployeesAtIndex index: Int) {
//NSLog("adding %@ to %@", p, employees)
let undo = self.undoManager
undo!.prepareWithInvocationTarget(self).removeObjectFromEmployeesAtIndex(index)
if !undo!.undoing {
undo!.setActionName("Add Person")
}
employees.insertObject(p, atIndex: index)
}
func removeObjectFromEmployeesAtIndex(index: Int) {
let p = employees.objectAtIndex(index) as! Person
//NSLog("Removing %@ from %@", p, index)
let undo = self.undoManager
undo!.prepareWithInvocationTarget(self).insertObject(p, inEmployeesAtIndex: index)
if !undo!.undoing {
undo!.setActionName("Remove Person")
}
employees.removeObjectAtIndex(index)
}
答案 2 :(得分:-1)
我认为完全取代传统的Objective-C NSUndoManager
方法是最干净的:
private class SwiftUndoPerformer: NSObject {
let closure: Void -> Void
init(closure: Void -> Void) {
self.closure = closure
}
@objc func performWithSelf(retainedSelf: SwiftUndoPerformer) {
closure()
}
}
extension NSUndoManager {
func registerUndo(closure: Void -> Void) {
let performer = SwiftUndoPerformer(closure: closure)
registerUndoWithTarget(performer, selector: Selector("performWithSelf:"), object: performer)
//(Passes unnecessary object to get undo manager to retain SwiftUndoPerformer)
}
}
然后你可以Swift-ly注册任何一个闭包,而不用担心包装东西以绕过一个过时的界面:
undoManager.registerUndo {
self.insertObject(person, inEmployeesAtIndex: index)
}