核心数据:禁用特定属性的撤消。推荐的方法不起作用

时间:2016-02-11 13:34:06

标签: ios swift cocoa core-data nsundomanager

我有一个文本字段和一个复选框,由核心数据支持。对复选框的更改应保留在任何撤消/重做操作之外。

推荐方法(在堆栈溢出时找到)是以下代码段。

@IBAction func stateDidChange(sender: NSButton?)
{
    //disable undo manager
    context.processPendingChanges()
    context.undoManager?.disableUndoRegistration()

   //set value
   let value = Bool(sender!.state == NSOnState)
   <some NSManagedObject>.flag = value

    //enable undo manager
    context.processPendingChanges()
    context.undoManager?.enableUndoRegistration()
 }

但这不起作用。当用户

  1. 编辑文本字段
  2. 更新复选框
  3. 并继续编辑文本字段
  4. 然后对撤消操作中包含对复选框的更改。

    我也试过

         NSNotificationCenter.defaultCenter().postNotificationName(NSUndoManagerCheckpointNotification, object: self.undoManager)
        self.undoManager?.disableUndoRegistration()
        //do work
        NSNotificationCenter.defaultCenter().postNotificationName(NSUndoManagerCheckpointNotification, object: self.undoManager)
        self.undoManager?.enableUndoRegistration()
    

    我甚至在NSManagedObject子类

    中尝试过它
        var flag : Bool {
        get {
            self.willAccessValueForKey("flag")
            let text = self.primitiveValueForKey("flag") as! Bool
            self.didAccessValueForKey("flag")
            return text
        }
        set {
            let context = self.managedObjectContext!
            context.processPendingChanges()
            context.undoManager?.disableUndoRegistration()
    
            self.willChangeValueForKey("flag")
            self.setPrimitiveValue(newValue, forKey: "flag")
            self.didChangeValueForKey("flag")
    
            context.processPendingChanges()
            context.undoManager?.enableUndoRegistration()
    
        }
    }
    

1 个答案:

答案 0 :(得分:1)

不是答案,但评论时间太长(编辑现在修改为真正的答案)。首先,我看到使用的方法可以正常工作,以阻止某些coreData操作出现在undo中。例如,我在创建新对象和在代码中设置初始状态时使用它。通过这种方法,我允许用户在此之后对对象进行编辑,但这些对象永远不能撤消到对象的初始默认状态之前。所以从这个意义上说,你的建议似乎是正确的。

...然而

我已经看过报告(但我自己没有测试过),CoreData撤消的行为与预期不同。我听说不是记录单个属性更改操作的反向操作,而是维护一堆对象状态。如果为真,这可能与您观察到的行为相符。

考虑一个标签= A且复选框= NO的对象。在启用撤消的情况下将标签设置为B.国家现在是B&amp;没有。这可以回滚到A&amp;没有。现在将复选框设置为YES而不撤消。国家现在是B&amp;是。如果现在调用撤销,则所需的状态将是A&amp;是的,但这种状态从未存在过。记录的状态堆栈是

B&amp;是&lt; - 当前状态

B&amp;不 - A&amp; NO&lt; - 过去状态的LIFO堆栈

然而正如我所说,我还没有真正测试过这个。我曾经用XML coreData商店做了一些不确定的测试,似乎表明还有更多的问题。另一方面,我可以想象,对于存储的SQLite,存储可能是正确的,这取决于CoreData如何使用底层SQL框架。应该进行测试。

如果确实如此,可以推测它是在逐个对象的基础上实现的,并且可以通过将不可撤销的动作放在一对一的子对象中来规避它。这样主要对象状态保持一致,在示例中是标签和对checkBoxObject的引用。然后,checkBoxObject的内部状态可能无关紧要,因为主对象中的引用是不变的。但必须对此进行测试。

UPDATE 在我最初的答案之后,我现在花时间测试所提出的假设并发现它是正确的。 CoreData似乎将undo实现为完整对象状态的LIFO堆栈。因此,不可能在一个对象内选择性地撤销某些属性。

我还测试了第二个假设,即这些状态LIFO堆栈是按对象的,因此可以通过将不可撤销的属性放在与原始对象1到1链接的单独对象中来规避这个问题。通过此设置,可以获得所需的行为。

对于XML和SQLite支持的CoreData存储,行为是相同的。

我进一步发现,要获得所需的行为,修改coreData属性的代码应该包含在撤消分组中,并且应该在撤消组关闭之前在托管对象上下文中调用-processPendingChanges

相关问题