0

In my iPhone app I am inserting lots of data after login by means of Core Data. Initially I was showing a loader while data was being inserted so the blocking of UI was not a matter, but now I removed the loader and moved all the insert operations on the background thread by changing the managedobjectcontext concurrency type to NSPrivateQueueConcurrencyType for some insertions to relieve the UI from the heavy insertion work.

I am wondering what will be the downside if I use this same context and NOT NSMainQueueConcurrencyType for all operations, is it recommended?

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
Firdous
  • 4,624
  • 13
  • 41
  • 80

4 Answers4

1

You SHOULD use NSPrivateQueueConcurrencyType for all of your contexts. NSFetchedResultsController, for example, does work fine with a private queue context as long as your observe all of the rules for using queue confinement (i.e. fetches must be performed through the queue, as well as faults, etc.). There is a bug with NSFetchedResultsController caching when using private queue contexts, but caching covers only a limited number of use cases.

If/when you are using data from Core Data to update UI elements, you will still have to access the UI from the main queue. For example, this would be accessing a property to update a label:

[[object managedObjectContext] performBlock:^{
    NSString *text  = [object someProperty];
    [NSOperationQueue mainQueue] addOperationWithBlock:^{
        [[self someLabel] setText:text];
    }];
}];

There are many advantages to using private queue confinement. The downside is that you will have to include code like that above - which far outweighs performing Core Data work on the main queue.

quellish
  • 21,123
  • 4
  • 76
  • 83
0

There is no downside as long as all operations that involve core data are performed on this context.

Perhaps a difference, but not really a downside is that you have to perform all your data operations asynchronously.

By the way, core data has its own "Background" thread, and as long as you perform all the operations with "performBlock" you will be fine.

What is NSManagedObjectContext's performBlock: used for?

Community
  • 1
  • 1
Pochi
  • 13,391
  • 3
  • 64
  • 104
0

The real detail you should tell us is what type of operations you are running.

If you don't touch the UI, it's ok to perform operations in a different thread. For example, say you are importing JSON data (a lot of them) from a back-end. Without it that app could freeze.

NSMainQueueConcurrencyType creates a context that is associated with the main dispatch queue and thus the main thread. You could use such a context to link it to objects that are required to run on the main thread, usually UI elements. SO, you need it for example when you deal with a NSFetchedResultsController.

Anyway, my personal advice is to profile the application and use threaded contexts whereas you find bottlenecks. Core Data could become quite complex. So stay simple whenever possible.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
  • apart from importing json data i also mean to use normal records fetching from core data in lists and view (to be moved in private context) – Firdous Sep 06 '14 at 09:24
0

I would say the downside is that you may not use NSManagedObjects you get hold of inside, outside of the -performBlock:. You will have to transport individual properties out of the block to pass the values to your UI elements, because you may not touch the UI directly from inside the -performBlock:.

Also, context of NSMainQueueConcurrencyType does not have a background queue. What -performBlock: does is queue the block for execution in the runloop cycle. So while it appears that the execution of the code continues from the statement, it will still block the thread later on once the block starts executing.

svena
  • 2,769
  • 20
  • 25
  • "I would say the downside is that you may not use NSManagedObjects you get hold of inside, outside of the -performBlock:". That's true for any context using queue confinement, wether a private queue or the main queue. – quellish Sep 06 '14 at 23:13
  • @quellish Yes of course. But it is common to retain access to your managed objects in your view controller code to mediate information flow between your model and UI elements. Using a context of main queue type, you can do so easily while with private queue you'll have to go around. – svena Sep 07 '14 at 17:04
  • If you are using an `NSMainQueueConcurrencyType` context you should still be accessing the context through `performBlock:` and `performBlockAndWait:`. Failing to do so can and will introduce some subtle bugs into your application, like inconsistent processing of user events. – quellish Sep 07 '14 at 20:13
  • @quellish In fact Apple's WWDC 2011 Session 315 states that on main thread you are OK to message managed objects directly outside of those block based methods for NSMainQueueConcurrencyType. That is also my experience. Please review it if in doubt. – svena Sep 07 '14 at 21:08
  • I'm not in doubt. It will execute, and as I said, it can and will introduce subtle bugs. You are better off explicitly using `performBlock:` or `performBlockAndWait:`. – quellish Sep 07 '14 at 22:29
  • @quellish I have to disagree. It has been brought up as a benefit of using NSMainQueueConcurrencyType context by Apple and during my many years of experience with Core Data in particular it has never resulted in bugs for me. – svena Sep 08 '14 at 04:11
  • The "benefit" is not having to write `performBlock:`. The downside is that the compiler and runtime have to reason about your intent with incomplete information, which is never a good thing. In this case, your Core Data operation may have an autorelease pool, it may not. It may process user events on the next iteration of the run loop, it may not. That will lead to subtle bugs in most applications that use Core Data, much like the difference between using `performBlock:` and `performBlockAndWait:`. – quellish Sep 08 '14 at 05:21
  • It has nothing to do with reasoning. It has everything to do with serialising access to a shared resource. And having it all on the main thread, does that for you so you are safe to access the managed objects outside of the block based API calls. – svena Sep 08 '14 at 06:43
  • it has everything to do with reasoning. Different code paths are executed when the context concurrency type is NSMainQueueConcurrencyType and the queue-based methods are not used to access it vs. when they are. – quellish Sep 08 '14 at 07:51