Search code examples
swiftcocoacore-datansmanagedobjectnsundomanager

How can I undo a NSManagedObject deletion without using the built-in undo manager?


I'm building an OSX document-based app using CoreData and NSUndoManager.

I have a global NSUndoManager that handles the Undoing and Redoing, instead of using the default one that's built into each NSManagedDocument. This means that I register the undos and redos manually, instead of relying on them to be automatically registered when the Managed Object Context changes.

When I delete the NSManagedObject from the NSManagedObjectContext, I want to register an undo that restores the deleted object. I know this is possible, because the NSManagedDocument's built-in NSUndoManager would do it by default, but trying to use the object after it's been deleted throws an error. How can I restore the actual object during the undo?

func removeAnObject(object: NSManagedObject) {
    self.managedObjectContext?.deleteObject(object)
    self.project?.undoManager?.registerUndoWithTarget(self, handler: { (object) in

        // how to undelete object???

        self.project?.undoManager?.prepareWithInvocationTarget(self).removeAnObject(object)
    })
}

Solution

  • Got it figured out. The easy answer:

    self.project.undoManager?.insert(object)
    

    The tricky part is, if you've saved the managed object context to a persistent store, all of the properties of "object" are blanked. If you save the values of those properties beforehand, though, you can reassign them after the new insert.

    func removeAnObject(object: NSManagedObject) {
    
        let property1 = object.property1
        let property2 = object.property2
    
        self.managedObjectContext?.deleteObject(object)
        self.project?.undoManager?.registerUndoWithTarget(self, handler: { (object) in
    
            self.managedObjectContext?.insertObject(object)
            object.property1 = property1
            object.property2 = property2
    
            self.project?.undoManager?.prepareWithInvocationTarget(self).removeAnObject(object)
        })
    }