Phineas Lue
Phineas Lue

Reputation: 317

Core Data and multiple thread programming

I know this is not a new topic, but I have not found a clear answer on my problem.

I am working on a project, which has a Core Data Model containing "Book". So when I downloading json data through network, I want to store these Book models in my core data (of course in background thread to not block the UI) and then pass these Book models to my controller and load table.

However, when I had learned the Core Data Reference of Apple, I get confused. The document says that I should not pass managed object between context. But I have two context, one for main thread and one for background thread which is used to download, store data and fetch current updated data. So what I should do is fetching managed object ids in background, and passing these ids to context in main thread, and then get managed object with these ids in main thread.

Here comes the problem. Would getting managed object with id in main thread block UI? When I get managed objects with their ids in main thread, am I accessing the SQLite? And if some of these fetched managed objects are fault, which means I may do IO if I want to get their property, I think it still block my UI.

So, what is a practical pattern to use Core Data to fetch data in background and show these data in main thread (UI operation should be in main thread) without blocking UI?

Thank you for any help!


Rethink:

Actually all the answers have not resolved my problem. However, I am back to a consideration that when we need to use multiple thread programming in core data. For most situation, maybe it is efficient enough to just use core data straight forward. I have overestimated the cost of core data operation in main thread.

However, still, I want someone to recommend a practical pattern to do fetch in background, and display in main thread. I would appreciate that!

Upvotes: 3

Views: 945

Answers (5)

Jody Hagins
Jody Hagins

Reputation: 28419

In your case, I would use three MOCs.

NSManagedObjectContext *worker = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyTyep];
worker.persistentStoreCoordinator = // your PSC
NSManagedObjectContext *main = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
main.parentContext = worker;

Then, whenever you want to perform background stuff, create a background MOC as a child of the main MOC.

NSManagedObjectContext *background = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
background.parentContext = main;

Remember, saving a context only saves one level. So, when you save the background context, changes will be automatically pushed into the main context.

You can then save the main context whenever you want... but at some point you need to save the worker context. UIManagedDocument handles the main/worker save interaction for you automatically (but you give up some control when using it).

The other benefit you get here is that the actual IO operations are not happening in the main thread.

Upvotes: 3

Nenad M
Nenad M

Reputation: 3055

I don't know if this will help you but give this blog entry over at the wonderful Cocoa is my girlfriend blog a try: Core Data and Threads, Without the Headache

It explains some approaches to this problem and also deals with the UI and main thread question.

Upvotes: 0

Dmitry Shevchenko
Dmitry Shevchenko

Reputation: 32434

First, keep it simple, you don't want juggle contexts in order to fix an issue you do not have. Yes, fetch on main thread will block UI, but unless you found this to be a real problem on real hardware, you can ignore it. If your fetch is indeed so heavy that it takes a noticeable amount of time, then profile and optimize, there are a lot of info out there, look at WWDC '12 videos on Core Data and Instruments and excellent Marcus Zarra book.

Upvotes: 1

TheEye
TheEye

Reputation: 9346

It all depends on how many inserts you do into your database.

I found it working best to do all the downloading in a background thread, and then insert the objects in the main thread. As long as it's only a few hundred updates every 30 minutes, you should be fine with the influence on the UI performance. In my experience the robustness and simpleness of doing it like that outweighs by far the small performance impact on your main thread - you don't have to care about synchronizing contexts, making sure you use the right object in the right thread etc.

Upvotes: 1

Jerome Diaz
Jerome Diaz

Reputation: 1866

You should perform your data downloading in your background thread and then perform your update / insert operation in your main thread

Upvotes: 0

Related Questions