本文介绍了NSUndoManager:捕获引用类型可能吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当值是引用类型时,我很难理解NSUndoManager如何捕获值.每当尝试使用undoManager时,这些值都不会撤消.

I am having trouble understanding how NSUndoManager captures values when the values are reference types. Whenever try to use the undoManager, the values don't undo.

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

Note: I need to support macOS 10.10, and I am using Swift 3 and XCode 8

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

Here I save the state of the ID numbers, reset them all to -1, and then try to undo. The result is that they are all still -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是值类型,因此效果很好.

To prove to myself that it was a problem capturing values, instead of saving the ID objects themselves, I stored the Int values that they contain. It worked perfectly as the Ints are value types.

然后,我阅读了有关闭包捕获的更多信息,并尝试了此方法.

Then I read some more about closure capturing and tried this.

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

相同的问题,仍然是-1.

Same problem, all still -1.

推荐答案

NSUndoManager并不是真的要捕获旧的,而是要捕获操作 em>恢复原始值.

NSUndoManager isn't really about capturing about old values, but about capturing operations that restore the original values.

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

You are only capturing references to the IDs. So the elements in savedIDs are pointing to the same objects as the id properties on the elements of people, i.e. when you change one, you also change the other.

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

What you need to do is manually save the IDs and the values you want to reset them to, like so:

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

这可以确保idnumber值本身保存在某个地方,而不仅仅是指向id的指针.

This ensures that the number value itself of id is saved somewhere, not just the pointer to the id.

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

You can then register an action that performs the undoing with the values you captured manually, like so:

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

这篇关于NSUndoManager:捕获引用类型可能吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 22:31