Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data - sharing NSManagedObjects among multiple threads

I suffered all the consequences of using a single MOC in multiple threads - my app crashes at random points because the MOC is created in the main thread and I also use it to fill the DB in another thread. Though the code is synchronized (@synchronize) using a global singleton the app crashes. I read that using a separate MOC for each thread will make things ok but I also read that it is considered also a bad approach to share NSManagedObjects across threads.

My use case is the following: 1)I load and parse XML from a server and during the parsing I insert each new NSManagedObject in the database. This all happens in a separate thread. 2)From the main thread the user interacts with the UI which reads data from the database.

In both threads I use NSManagedObjects. How would you suggest me to fix this? I failed multiple times already.

Most often the app creashed with error suggesting that I am modifying a collection while enumerating it which is not true as the code is synchronized and while I am iterating it no modifying happens and vice versa - while I modify it I don't iterate and I save once I am done.

like image 857
gop Avatar asked Oct 13 '12 15:10

gop


People also ask

How does Core Data handle multithreading?

To use Core Data in a multithreaded environment, ensure that: Managed object contexts are bound to the thread (queue) that they are associated with upon initialization. Managed objects retrieved from a context are bound to the same queue that the context is bound to.

What we can pass from one thread to another in Core Data in multithreaded environment?

If you need to pass a managed object from one thread to another, you use a managed object's objectID property. The objectID property is of type NSManagedObjectID and uniquely identifies a record in the persistent store.

Can we use Core Data managed objects from background thread?

There are multiple ways to use Core Data and a NSManagedObjectContext on a background thread. One way is the performBackgroundTask(_:) method on an NSPersistentContainer : // Spawns a new thread and creates a background // managed object context to perform operations // in the background persistentContainer.

What is NSManagedObjectContext in Core Data?

An object space to manipulate and track changes to managed objects.


2 Answers

Use one NSManagedObjectContext per thread. If you communicate between threads, pass the NSManagedObjectID, which is thread safe, and fetch the object again from you thread context. In my apps I sometimes even use one context per controller.

To manage the different contexts, register an Observer for the NSManagedObjectContextDidChangeNotification. Within this notification handling, you pass the notification to each of your contexts via the mergeChangesFromContextDidSaveNotification: method. This method is thread save and makes the context update its state.

After this you have to refresh your views. If you have a table view based application, have a look at NSFetchedResultsController. This helps you update the table automatically with appropriate animations. If you don't use table views, you have to implement the UI update yourself.

like image 150
Michael Ochs Avatar answered Oct 08 '22 11:10

Michael Ochs


If you are only supporting iOS 5 and above you don't need to deal with NSManagedObjectID and merging contexts anymore. You can use the new concurrency types of NSManagedObjectContext instead. Then do your operations within managedObjectContext:performBlock and they will be merged automatically.

See the answer from svena here for more information: Core Data and Concurrency using NSOperationQueues

like image 35
Kim Avatar answered Oct 08 '22 12:10

Kim