0

I need to be able to to grab objects from Core Data and keep them in a mutable array in memory in order to avoid constant fetching and slow UI/UX. The problem is that I grab the objects on other threads. I also do writing to these objects at times on other threads. Because of this I can't just save the NSManagedObjects in an array and just call something like myManagedObjectContext.performBlock or myObject.managedObjectContext.PerformBlock since you are not supposed to pass MOCs between threads.

I was thinking of using a custom object to throw the data I need from the CD objects into. This feels a little stupid since I already made a Model/NSManagedObject class for the entities and since the custom object would be mutable it still would not be thread safe. This means I would have to do something like a serial queue for object manipulation on multiple threads? So for example any time I want to read/write/delete an object I have to throw it into my object serialQueue.

This all seems really nasty so I am wondering are there any common design patterns for this problem or something similar? Is there a better way of doing this?

Cristik
  • 30,989
  • 25
  • 91
  • 127
boidkan
  • 4,691
  • 5
  • 29
  • 43
  • You might also want to take a look at this SO question: http://stackoverflow.com/questions/14284301/correct-implementation-of-parent-child-nsmanagedobjectcontext. – Cristik Jan 13 '16 at 00:33

2 Answers2

5

I doubt you need custom objects between Core Data and your UI. There is a better answer:

  1. Your UI should read from the managed objects that are associated with the main thread (which it sounds like you are doing).
  2. When you make changes on another thread those changes will update the objects that are on your main thread. That is what Core Data is designed to do.
  3. You just need to listen to those changes and have your UI react to them.

There are several ways to do this:

  • NSFetchedResultsController. Kind of like your mutable array but has a delegate it will notify when objects change. Highly recommended
  • Listen for KVO changes on the property that you are displaying in your UI. Whenever the property changes you get a KVO notification and can react to it. More code but also more narrowly focused.
  • Listen for NSManagedObjectContextDidSaveNotification events via the NSNotification center and react to the notification. The objects that are being changed will be in the userInfo of the notification.

Of the three, using a NSFetchedResultsController is usually the right answer. When that in place you just change what you need to change on other threads, save the context and you are done. The UI will update itself.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • `NSFetchedResultController` was exactly what I needed. I can't believe I haven't run into/read about this yet... – boidkan Jan 13 '16 at 17:01
-2

One pattern is to pass along only the object ids, which are NSString objects, immutable and thus thread safe, and query on the main thread after those ids. This way every NSManagedObject will belong to the appropriate thread.

Alternatively, you can use mergeChangesFromContextDidSaveNotification which will update the objects from the main thread with the changes made on the secondary thread. You'd still need fetching for new objects, though.

The "caveat" is that you need to save the secondary context in order to get your hands on a notification like this. Also any newly created, but not saved objects from the main thread will be lost after applying the merge - however this might not pose problems if your main thread only consumes CoreData objects.

Cristik
  • 30,989
  • 25
  • 91
  • 127
  • Right, I understand that but the problem is that then I have to fetch the object. Or is `objectWithID(ObjectId)` super efficient compared to executing a fetch? – boidkan Jan 12 '16 at 23:42