Add undoManager feature as in CoreData
Thanks for the feature request, @anbarasu0504. We have a number of high priority features we'd like to build before diving into something like this, but it would certainly be nice to have at some point.
If you, or anyone, feels like contributing to this, please start with a design proposal in this issue demonstrating how the feature should work, which API it should expose and how to deal with potential pitfalls:
@jpsim any chance you might escalate this?
No, we still have a number of high priority features we want to tackle before dedicating resources to this. But my comment above does provide some guidance as to how an external contributor could get started with this.
Any further thoughts or update on this? It's the last thing that is holding up my adoption of Realm on a few projects.
@andrewebling it's fairly difficult to build undo in a general-purpose API, but relatively easy to build it in a domain-specific setting, so I'd encourage you to build undo functionality on top of Realm yourself for your specific app's needs.
For example, instead of storing values, store operations (insert string, remove string, etc.). You can then compute the final value by applying all these operations. You could also trim the history as you see fit on a recurring basis. You could then more easily track what things you want to "roll back", what points in time make sense as discrete "checkpoints", etc.
I built a drawing app using Realm (Similar to Realm demo app but on a map). I needed an undo queue because, well, users expect it when drawing. I was dreading the implementation because it's kind of complicated. But... It turned out to be easy with Realm! Especially if you have primary keys.
I have an object:
class Line: Object {
@objc dynamic public var lineID: String?
@objc dynamic public var strokeStyleRaw: String?
@objc dynamic public var strokeHexColor: String?
@objc dynamic public var lineTypeRaw: String?
public let points = List<MyPointObject>()
override static public func primaryKey() -> String? {
return "lineID"
}
}
Right before you do anything that could need an undo, create an unmanaged copy of the object using realm convenience initializer.
//myManagedLine is the `Line` object you are working on that is part of a Realm.
let copy = Line(myManagedLine)
Then append the new unmanaged object to an array
//Array is probably declared at the top of your `UIViewController`
let myUndoArray = [Line]()
//"Push" copy on to the array
myUndoArray.append(copy)
//Change the managed line object
Realm().beginWrite()
myManagedLine.points.append(NewPoint)
try! Realm().commitWrite()
Now, when the user presses the undo button you just pop off the last object in the undo array and save it using the add with update function.
let revertedLine = myUndoArray.removeLast()
Realm().beginWrite()
Realm().add(revertedLine, update: true)
try! Realm().commitWrite()
Magic!! The myManagedLine object is now reverted. So, bottom line. Just push an unmanned copy of the object you want to "Undo" onto a queue. On undo, just save it again! All assuming you are using the primary keys.
Any updates on this?
Closing this as it's not expected to happen in any foreseeable future.
Most helpful comment
I built a drawing app using Realm (Similar to Realm demo app but on a map). I needed an undo queue because, well, users expect it when drawing. I was dreading the implementation because it's kind of complicated. But... It turned out to be easy with Realm! Especially if you have primary keys.
I have an object:
Right before you do anything that could need an undo, create an unmanaged copy of the object using realm convenience initializer.
Then append the new unmanaged object to an array
Now, when the user presses the undo button you just pop off the last object in the undo array and save it using the add with update function.
Magic!! The
myManagedLineobject is now reverted. So, bottom line. Just push an unmanned copy of the object you want to "Undo" onto a queue. On undo, just save it again! All assuming you are using the primary keys.