Core Data object creation/edition view with undo capabilities but without headache
Never wonder again how to handle editing your
NSManagedObject instances. This design pattern will improve your code, reduce the amount of lines to write and give you great extensibility, as long as you do not require iOS 4 support.
I know that an iOS 5 feature is not fresh news, and a lot of you guys already know this pattern very well. But I’ve found out that it is always treated like an “everybody-knows this” feature, and new developers might miss this one.
I’m assuming that you are already familiar with Core Data and that you know the purpose of a
NSManagedObjectContext. If not, please read the Core Data Tutorial for iOS or if you are in a hurry skip the tutorial and read the NSManagedObjectContext reference introduction.
Analyze the problem
We want to let the user be able to modify some properties on an
NSManagedObject instance, but still be able at the same time to rollback these modifications.
Nested contexts. Thank you Apple.
Create the right context type
To use nested contexts you need to create a child
NSManagedObjectContext with the right context type, otherwise changes won’t be merged when you want to save.
NSManagedObjectContext instance can be initialized with a concurrency type, see the
There is three type available to us
- NSConfinementConcurrencyType (default)
Which one to choose ?
It can only be used within the thread where it has been created. It seems good enough for our case, and is the default type by the way, but it won’t work because :
NB if you want to use a context as a nested context you need a “queue context”. So
NSConfinementConcurrencyTypeis not enough.
Very good for performance optimization when you need to perform some work on data, it uses a private queue and you need to use
performBlockAndWait: to run some code inside the so called private queue. For the record, that’s what project like RestKit or AFIncrementalStore are using behind the scene.
As the type name implies, this context would be associated to the main dispatch queue (and not a private queue as seen previously). So this is perfect if your managed object properties are used in some UI elements… which is our case !
Now we know how to intialize our child managed object context :
Pass objects between different contexts
If you ever tried to pass a
NSManagedObject instance between two different contexts it will raise a
NSManagedObject instances you need to pass a
NSManagedObjectID instance, and only then fetch the object in the other context.
To undo or not to undo
The undo part is so simple, you just need to throw the context away because it encapsulates all the changes that had been made.
When you want to save, just invoke the
save: method of the child context, and it will propagate the changes up to the parent context. The way the properties that will be merged, will depend on the parent context
mergePolicy property. You can find the detail of each merging policy in the NSManagedObjectContext reference.
However, the most widely used merge policy is NSMergeByPropertyStoreTrumpMergePolicy.
Tips I’ve taken the good habit of writing a small display error message code along with the usual
NSLogline. This is a good behavior because we usually tend to say “I will come back later to handle properly the error”, but we never came back! Right?
So why not write this one line of code that will not handle anything but at least let the user know that an error has occurred. And to do that I’m using the excellent SVProgressHUD project by Sam Vermette.
So now you have all the pieces to make a great creation/edition view with save and cancel functionalities, and with so little code that you will feel light and full of joy!comments powered by Disqus