Description
NSPersistentContainer instance methods performBackgroundTask(_:) and newBackgroundContext() poorly documented.
No matter which method you call, in any case, the (returned) temporary NSManagedObjectContext configured using privateQueueConcurrencyType and is directly related to NSPersistentStoreCoordinator and therefore does not have a parent .
See documentation :
Calling this method causes the persistent container to create and return a new NSManagedObjectContext with the concurrencyType parameter set to privateQueueConcurrencyType. This new context will be directly associated with NSPsistentStoreCoordinator and configured to consume NSManagedObjectContextDidSave is automatically translated.
... or confirm yourself:
persistentContainer.performBackgroundTask { (context) in print(context.parent) // nil print(context.persistentStoreCoordinator) // Optional(<NSPersistentStoreCoordinator: 0x...>) } let context = persistentContainer.newBackgroundContext() print(context.parent) // nil print(context.persistentStoreCoordinator) // Optional(<NSPersistentStoreCoordinator: 0x...>)
Due to the lack of parent changes will not be bound to the parent context , for example, for example. viewContext and with viewContext intact, the connected NSFetchedResultsController does not recognize any changes and therefore does not update or call its delegate methods. Instead, the changes will be transferred directly to the persistent store coordinator and then saved to the persistent store .
I hope that I was able to help you, and if you need more help, I can add how to get the desired behavior, as described by you, to my answer. ( Solution added below)
Decision
You achieve the behavior you described using two NSManagedObjectContext with a parent-child relationship:
// Create new context for asynchronous execution with privateQueueConcurrencyType let backgroundContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) // Add your viewContext as parent, therefore changes are pushed to the viewContext, instead of the persistent store coordinator let viewContext = persistentContainer.viewContext backgroundContext.parent = viewContext backgroundContext.perform { // Do your work... let object = backgroundContext.object(with: restaurant.objectID) backgroundContext.delete(object) // Propagate changes to the viewContext -> fetched results controller will be notified as a consequence try? backgroundContext.save() viewContext.performAndWait { // Save viewContext on the main queue in order to store changes persistently try? viewContext.save() } }
However, you can also use performBackgroundTask(_:) or use newBackgroundContext() . But, as said earlier, in this case the changes are saved in the permanent storage directly, and viewContext not updated by default. To propagate the changes to viewContext , which triggers the NSFetchedResultsController notification, you must set viewContext.automaticallyMergesChangesFromParent to true :
// Set automaticallyMergesChangesFromParent to true persistentContainer.viewContext.automaticallyMergesChangesFromParent = true persistentContainer.performBackgroundTask { context in // Do your work... let object = context.object(with: restaurant.objectID) context.delete(object) // Save changes to persistent store, update viewContext and notify fetched results controller try? context.save() }
Note that extensive changes, such as adding 10,000 objects at the same time, most likely make your NSFetchedResultsController crazy and therefore block the main queue .