views:

372

answers:

1

Hi,

I have a Core Data based iPhone application that needs to save 1000 managed objects on termination. This takes 8+ seconds, however, the OS kills the app if it does not complete in approx. 6 seconds.

I don't want to save the objects earlier, because then the user has to wait 8 seconds longer for the results to display.

Is it possible to somehow save the objects earlier in a background thread, while still having (read-only) access to the NSManagedObjectContext in the main thread to display the data? Or is it somehow possible to duplicate the managed objects, and pass the duplicates to a background thread for saving?

For clarification, here is what happens in the application now: I have a background thread that imports 1000+ objects in about 1 sec. If I save while importing, it takes a lot longer than 1 sec. So in order to display those items with minimum delay, the context is handed off without saving to the main thread, and the user gets his results as fast as possible.

I now have the problem how to save these objects without the user having to wait the 8 secs. If I save in the background thread before handing over, the user has to wait. If I save in the foreground thread after handing over, the user has to wait. The only two possible approaches I can see right now are:

  1. Somehow having core data doing its sqlite accesses in the background, while still keeping the main thread reactive
  2. Handing the objects unsaved from one context to another, and saving in the background thread

Both approaches seem impossible (at least according to the Core Data documentation). So is there no other solution than to have the user wait longer (and maybe display a nice rotating hour glass :-)?

Regards, Jochen

+4  A: 

Yes, there's a way to save the managed object context from the background thread, or more precisely, it's usually referred to as "importing in the background thread, and showing in the main thread." This way, the managed objects are saved piece by piece when they are imported, not all at one time at the termination.

I just wrote an short answer on a similar question here at SO, but you should read this Apple doc. There're many potential pitfalls, so read very, very carefully. And then read this Apple doc called "efficiently importing data". This is also a must-read! And Marcus Zarra's CoreData book is also helpful.

CoreData multithreading is a bit tricky, but it really pays off. Good luck!

Yuji
Agreed. Saving them while doing the import is far more efficient than doing a massive save on exit. I also did a nice import walkthrough over on Mac Developer Network that even explains how to do background saving.
Marcus S. Zarra
Thanks for the help. I tried saving while importing, with the result that import time goes up. It's faster than saving at the end, but still not fast enough. I've clarified the question on this matter, and I sure agree that Core Data multi-threading is tricky...
Jochen
Your 1. should be possible. Just make one `NSManagedObjectContext` per thread. And while importing in the background, don't create all 1000+ entities at once and save it at once. Instead, create 10 entities in the context, save them, pass them to the main thread, and repeat this process. The user can't see 1000+ entries at the same time in any case, so you can fool your user that way that all the data is available.
Yuji
Thanks, that's what I'm doing right now. I still need to calculate some summary data out of the 1000 entries to display, so the user still has to wait longer. But he sees some data in the meantime.
Jochen