views:

1222

answers:

1

I am working on a non-document-based Core Data application.

I would like changes to be saved as they happen. This is what the user expects in this type of application. It is also what Apple has implemented in iPhoto or iTunes.

A brute force approach would be to set up a timer to save frequently. The method triggered by the saving would then swallow all validation errors so as not to bother the user. Only upon quitting, the user will be bugged to arrange the data so it can save. IMHO, that approach stinks.

So I am thinking, there must be a way to somehow hook saving to something like the NSEditor protocol. Every time the user (or a controller) finishes editing data, the application delegate should somehow be notified an trigger a save operation. Thing is I don't quite know where to look.

I would think that for more complicated operations, which may require some cross-validations to go through, I would present the user with bit of interface tied to a dedicated NSManagedObjectContext.

+5  A: 

At the end of each event in an AppKit app, CoreData will run a -processPendingTransactions for you.

One side-effect of this is that if you've registered with your NSManagedObjectContext to receive change notifications, you'll get called at the end of each event.

So, for instance, in your notification handler, you could call just tell the context to save.

However, you might be paranoid about doing a save on a context while in a callback from that same context, so you'd probably feel better if you did a performSelector:@selector(save:) afterDelay: to push the save until after the -processPendingTransactions is done.

You could even do a cancel previous on the -save: selector and have the delay be like 5 seconds, so if the user or app is in the middle of a BUNCH of changes they'll all coalesce into a single save.

And, in fact, that's exactly how Delicious Library 1.0-1.09 worked.

-Wil

Wil Shipley
Thanks for the tip. Both your suggestion and the idea of piggybacking onto the undo manager seem excellent.Of course, your comment begs a question: why do more recent versions of Delicious Library no longer use this technique?
Pierre Bernard
I decided to try saving immediately instead of after a delay, because I am running in multiple threads at once and when, for instance, you create a cover in the main thread, you REALLY want the background graphic threads' managedObjectContexts to see the cover immediately, not in three seconds when you auto-save.
Wil Shipley
So Wil do you still call performSelector:@selector(save:) afterDelay: at all or are you using some other method to autosave the context?
John Wright
I manually processPendingChanges and save at certain choke points in my code, since processPendingChanges is needed to update the UI when I add or remove and object anyhow.
Wil Shipley
I used this method in an iPhone/iPad app just now. At first I saved right away without using the "performSelector" technique and it seemed fine - but I got too nervous after reading the docs (they say that will cause in infinite loop), so I changed to the performSelector method with a 0.05s delay.
Jason