NSUndoManager:可以捕获引用类型



当值是引用类型时,我无法理解NSUndoManager如何捕获值。每当尝试使用撤消管理器时,值都不会撤消。

注意:我需要支持 macOS 10.10,并且使用的是 Swift 3 和 XCode 8

在这里,我保存ID号的状态,将它们全部重置为-1,然后尝试撤消。结果是它们仍然是 -1。

import Cocoa
class Person: NSObject {
    var id: ID 
    init(withIDNumber idNumber: Int) {
        self.id = ID(idNumber)
    }
}    
class ID: NSObject {
    var number: Int
    init(_ number: Int) {
        self.number = number
    }
}
ViewController... {
    @IBAction func setIDsToNegative1(_ sender: NSButton) {
        var savedIDs: [ID] = []
        for person in people {
            savedIDs.append(person.id)
        }
        undoManager?.registerUndo(withTarget: self, selector:#selector(undo(savedIDs:)), object: savedIDs)
        for person in people {
            person.id.number = -1
        }
    }

   func undo(savedIDs: [ID]) {
         for id in savedIDs {
              print(id.number)
         }
         //Prints -1, -1, -1
    }
}

为了向自己证明捕获值是一个问题,我没有保存 ID 对象本身,而是存储了它们包含的 Int 值。它完美地工作,因为 Ints 是值类型。

然后我阅读了更多关于闭包捕获的信息并尝试了这个。

undoManager?.registerUndo(withTarget: self, handler: { [saved = savedIDs] 
    (self) -> () in 
         self.undo(savedIDs: saved)
 })

同样的问题,都还是-1。

>NSUndoManager并不是真正捕获旧,而是捕获还原原始值的操作

您只捕获对ID的引用。因此,savedIDs中的元素指向与people元素上的id属性相同的对象,即当您更改一个时,您也会更改另一个。

您需要做的是手动保存ID和要重置它们的值,如下所示:

let savedPairs = people.map { (id: $0.id, originalValue: $0.id.number) }

这可确保idnumber值本身保存在某个位置,而不仅仅是指向id的指针。

然后,您可以注册一个操作,该操作使用手动捕获的值执行撤消,如下所示:

undoManager.registerUndo(withTarget: self) {
    savedPairs.forEach { $0.id.number = $0.originalValue }
}

相关内容

  • 没有找到相关文章

最新更新