views:

345

answers:

1

I am trying to figure out the proper way to use NSManagedObjectContexts when you are viewing, editing, and creating NSManagedObjects. I feel that the documentation and examples have explained how to use them in the most basic cases, but I'm not sure what the proper methods are in a slightly more complex setup.

The setup:

  • 3 main screens: a list of objects, an edit object screen, and a new object screen.
  • Another thread is downloading objects to add to the list in the background.

The requirements:

  • The list screen uses a MOC and an NSFetchedResultsController to get all it's objects.
  • The edit and new object screens use MOCs to save/delete objects AND use NSFetchedResultsControllers for relationships.
  • The downloaded objects need a MOC to save it's objects into Core Data (on the main thread).

The questions:

  • How many MOCs do I need?
  • How should I manipulate these MOCs?

Possible Answers:

  • Have one "View" MOC that is never edited and is used in the list screen. Use separate MOCs for the edit, new object screens, and the downloads. When these MOCs save, merge the changes back to the "View" MOC. This way any changes don't affect the "View" MOC until they are saved. This is what I have been doing; it doesn't seem to be working as smoothly as I hoped. There is a disconnect between the editing and the viewing and instead of being able to check on things when I know they might of changed I have to wait for NSFetchedResultsController delegate methods to finish and check on every possible thing that might have changed. It also makes it difficult if I need to change some data in the list view.

  • Have one MOC for everything. This is what I first tried but wasn't sure of how to deal with the editing and creating. Now that I understand a bit more, I guess I could just edit the object or create an object and rollBack on cancel. On cimgf, I saw a post that seemed similar which said to create an undoGrouping around the edit/create and undo on cancel. Then I guess I could use a separate MOC on the downloaded objects because it might finish and save while the user is editing in the main MOC.

  • Anyways, the point is that I don't know what the proper method is. Can you help me?

Example Disconnect for First Possible Answer

  1. Created an object (1) in the edit moc. Saved. Merged with view moc by notification.
  2. Created a new moc because I am downloading objects in the background. Updated some objects that are related to (1). Saved. Merged with view moc by notification.
  3. Edit (1) in the edit moc. Saved. Merged with view moc by notification.
  4. PROBLEM: Because the edit moc never got the new moc changes, when it saves, it deletes all the new moc changes affected by it.
  5. SOLUTION: I realize that I could also merge the changes to the edit moc or always use a new moc to edit things. However, I keep running into little things like this and having to find solutions, so it leaves me to believe that this is not the best answer.
+2  A: 

You should have at least one MOC per thread (they are not thread safe). So you could have a MOC for the downloader (in the background thread) and another in for the activity in the main thread list, edit and new.

When you say there is a disconnect, can you be more specific? Are you using notifications (NSManagedObjectContextDidSaveNotification) and doing mergeChangesFromContextDidSaveNotification when you receive that notification. Remember, that mergeChangesFromContextDidSaveNotification should be performed on the main thread.

In your view controller with NSFectchedResultsController are you handling all the cases of the NSFetchedResultsControllerDelegate correctly?

lyonanderson
Thanks for replying.Yes, I am using notifications to update the view moc in the main thread.Yes, I am handling the NSFetchedResultsControllerDelegate cases correctly.I added an example of a disconnect to the question.So far this seems to be the best solution: - Use 1 moc for as much as you can. - If you can't use the main moc, create a new one *every time* you need to change something to avoid saving over changes made else where. Or merge changes to that moc as well if you can. - Any mocs besides the main one should merge changes to the main one.Is this what you have found?
jasongregori
Something like that. I had a main moc which was used by the NSFetchedResultController. Background activity (packaged in NSOperations) had their own moc. Any changes made in those mocs were passed using notifications to the main moc and merged. So essentially the main moc was readonly. This stuff is tricky and it took a while to get it just right. Lots of trial and error.
lyonanderson