I’ve been able to confirm this on my application, and a quick sample application I created to confirm this. Here’s the setup:
You have two managed object contexts:
masterMOC: NSPrivateQueueConcurrencyType, tied to persistent store coordinator
mainMOC: NSMainQueueConcurrencyType, child of masterMOC, NOT tied to any store coordinator
This setup was inspired from the WWDC video, which suggests we can save on a background thread by setting the masterMOC to a private queue and tie it to the persistent store. If you set up an NSFetchedResultsController using the mainMOC (and it must be the mainMOC since that’s the one tied to the UI), and set a fetchBatchSize, the batch size is disregarded and all entities are faulted in at once. I enabled the SQLite debug annotations, and when scrolling through thousands of rows (with a batch size of 20), no faults are fired what so ever.
If I make one simple adjustment, namely tie the persistent store coordinator to the mainMOC and make it a root context (that is, it is no longer a child of master), then the batch size works perfectly, and as I scroll through thousands of rows, several faults are fired.
Is this expected behavior? Am I missing something?
You can download the sample project here
There is limited discussion of nested contexts in the documentation, it only appears in “Core Data Release Notes for iOS v5.0”, and in
UIManagedDocument. The only comment on fetching and nested contexts is:Given the lack of any disclaimers relating to the functionality of batch fetching with nested contexts, I would suggest it is not expected that batch fetching and nested contexts are incompatible. However this seems to be the case as the most basic example does not function. (See test code below).
There is also an open radar submission describing the same problem here: http://openradar.appspot.com/11235622, and other problems noted with FetchedResultsControllers and nested contexts: Duplication of entity when change made by a child ManagedObjectContext is pushed (saved) to its parent.
A possible partial solution could be to add an additional
NSManagedObjectContextofNSMainQueueConcurrencyTypedirectly to the sameNSPersistentStoreCoordinatorfor the sole purpose of serving theNSFetchedResultsController. ObjectIDs could then be handed back to the nested child context when the user selects items, and any subsequent editing can then be performed in the nested contexts.This obviously reduces the benefit of using nested contexts and would require more frequent saving to synchronise between the nested contexts and the
NSFetchedResultsControllerscontext. However depending on the design of the application and the relative benefits of nested contexts vs batch loading this may be useful. (See example code below)Test code showing failure of simplest case batch fetching in nested contexts:
Example code showing use of an additional context to serve an
NSFetchedResultsControllerwith batching working: