Mike
Mike

Reputation: 1778

iPhone Core Data and Multithreading

I have an iPhone application I am developing which transfers data over the network and saves the data received in core data object for use later on. Presently. it works correctly in a single thread but I am working on converting the data transfer mechanism to run in a separate worker thread.

I've read the core data programming guide on multithreading and I'm planning on using separate managed object contexts for each thread and a single persistent store coordinator as seems to be recommended by Apple.

The application's main thread will never need to create or delete core data objects and will instead ask the worker thread. It will mostly be reading the objects and occasionally modifying them. It will also periodically ask the worker thread to fetch new objects or updates for existing objects from the network.

My question involves what I need to do to support this. The multithreading section of the core data programming says that I can "pass" objects between the two threads by passing object IDs. I'm a little confused as to exactly what I need to do. Do the two threads each have their own copy of each object the have fetched? If so, how are they synced? Are you supposed to explicitly fault objects you know the other thread has modified to get them to reload?

Let's say I am using an object in the main thread, and the worker thread modifies it. Is it enough to have the worker thread inform the main thread that the object was modified so the main thread can fault it forcing a reload? Or will it be faulted automatically? Or maybe this whole scenario is a bad idea and would cause an execption?

I'm thinking of implementing this by having a dictionary in the main thread of all the objects that are presently being used. When the worker thread modifies one, presumably because it fetched an updated version from the network, I am going to have it signal the main thread and the main thread can fault the object if it is currently on its list of objects it is using. Does this sound like a good idea, or is it even necessary?

Upvotes: 4

Views: 665

Answers (1)

ImHuntingWabbits
ImHuntingWabbits

Reputation: 3827

A couple of key points to remember:

  1. Only share object ID's between threads
  2. Use NSManagedObjectContextDidSave notifications in conjunction with the NSManagedObjectContext method mergeChangesFromContextDidSaveNotification: or refreshObject:mergeChanges:
  3. Spend some time writing code to resolve merge errors (i.e. resetting the object and attempting the merge again, etc.)

You seem to have the basics correct, usually where it gets tricky is with merging objects that have been modified in both threads. In that case you'll have to reset the object to be merged, merge it with the notifying thread's changes, and then reapply any local changes if so desired. There are a couple of API methods which can help you in this case:

  1. NSManagedObject#changedValues will give you a dictionary of all the changed properties which you can stash to reapply after the merge. Iterate through it's keys and call NSManagedObject#setValue:forKey: to re-apply the values.
  2. As mentioned before, NSManagedObjectContext#refreshObject:mergeChanges:, this method is best to use when you know that the threads didn't touch any of the same properties. In some cases this is guaranteed by design (network thread only updates timestamp, etc.).

Finally, encapsulating your processing code in an NSOperation will make it very easy to control the object lifecycle of your thread-local managed object context as well as any memory you might chew up as a result of the parsing.

Upvotes: 3

Related Questions