Core Data viewContext not receiving updates from newBackgroundContext() with NSFetchedResultsController
Asked Answered
E

4

35

In my application, I have a NSFetchedResultsController to load Core Data objects in a UITableView. The fetch request associated with this FRC uses the new viewContext property available for the NSPersistentContainer (iOS10).

When I select a cell, I pass the Core Data object to a new ViewController. This new VC still uses the viewContext. From this ViewController, I can update the Core Data object from ViewControllers presented modally. To do so, I use newBackgroundContext() for the modal ViewControllers. I can save the update Core Data object without any issue.

The problem is that the FRC is not automatically updated with the update Core Data object from the background context. It is as if the viewContext was not receivng and handling the Core Data object updates.

If I set automaticallyMergesChangesFromParent to true for the viewContext (app wide), the FRC gets the updated Core Data object when I save the background context. From my understanding, the viewContext should manage the merge of data automatically. The documentation describes the viewContext with: "This context is configured to be generational and to automatically consume save notifications from other contexts."

Can you clarify how to handle the different contexts with a NSFetchedResultsController?

Elanaeland answered 6/9, 2016 at 12:10 Comment(0)
P
37

You're seeing the correct behavior. If you want your viewContext to automatically pick up changes from other contexts, including ones created by newBackgroundContext(), you have to set automaticallyMergesChangesFromParent to true.

I agree that the docs are confusing on that point, "...and to automatically consume save notifications from other contexts."

Predicament answered 30/9, 2016 at 20:20 Comment(2)
Worked for me, just make sure you apply the setting to your parent viewContext.Frissell
Not working for me :( Can you pls check this #56836984Bridoon
A
13

Automatically merge changes from parent needs to set on the viewContext like this:

persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
Adhamh answered 30/12, 2016 at 7:35 Comment(0)
C
10

I haven't run into this directly, but your issue strikes me as odd if the newBackgroundContext were in fact layered under the viewContext since any save from the new context would only update the viewContext, which would also have to do its own save to get the changes to the persistent store (which you say is occurring properly). Based on that suspicion, I looked at the developer docs where Apple says:

Invoking this method (newBackgroundContext() ) causes the persistent container to create and return a new NSManagedObjectContext with the concurrencyType set to privateQueueConcurrencyType. This new context will be associated with the NSPersistentStoreCoordinator directly and is set to consume NSManagedObjectContextDidSave broadcasts automatically.

Thus, it would not be in a parent - child relationship with the viewContext. Based on the guidance, it seems the new context would be notified of changes by the old, but not vice versa, so you'd have to do a refresh on the viewContext when the new context changes, which you could do programmatically if you can track that in your code or perhaps use one of the change notifications in NSManagedObjectsContext to trigger the action.

Csch answered 9/9, 2016 at 0:36 Comment(1)
The documentation (in NSManagedObjectContext.h) for .automaticallyMergesChangesFromParent says: "Whether the context automatically merges changes saved to its coordinator or parent context. Setting this property to YES when the context is pinned to a non-current query generation is not supported". So it looks like the case of no parent is covered by "the store coordinator". .viewCoordinator and .newBackgroundContext share the same store coordinator (I just checked it). So setting .automaticallyMergesChangesFromParent would result in the expected behavior.Fineman
M
0

Not worked for me, So I changed save block from

self.persistentContainer.performBackgroundTask { (context) ... }

to

self.persistentContainer.newBackgroundContext().performAndWait { ... }

and of corse setting true automaticallyMergesChangesFromParent to make auto merge work.

lazy var viewContext: NSManagedObjectContext = {
    self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
    self.presistentContainer.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
    return self.persistentContainer.viewContext
}()

I don't know why the context from performBackgroundTask not merged to viewContext.

Monomorphic answered 9/9, 2018 at 13:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.