I have two managed object contexts and I want to use each one for fetch
vs update
as commonly advised.
However, all my attempts to utilize newBackgroundContext()
to save my data have failed. performBackgroundTask
also hasn't worked.
I am successful in saving using viewcontext
(the code below is successful), but it defeats the purpose of having background save capability. Plus, it could result in bad performance in future.
I already tried setting automaticallyMergesChangesFromParent = true
on my both contexts, but to no avail.
CoreDataManager
in my below code is a boilerplate class setting up the lazy vars returning persistentContainer
and context
objects.
Is there a proper way to indicated anywhere how to handle this standard problem?
PS: When I try inserting a bulk of objects using my newBackgroundContext()
, it just works OK. Update is the only problem - probably because it involves fetch which is handled by viewContext
.
PS+: For that matter, if I use newBackgroundContext()
for fetch and save both (just in the below function, not in my UI), it works too. But I do not know if this is recommended approach.
PS++: I also tried wrapping newBackgroundContext()
under a lazy var, so as not to create a new one every time, which anyway happens inside performBackgroundTask
- but this approach still does not save successfully.
class func updateRecord(recordId: String, data: Data)
{
let fetchRequest = NSFetchRequest<MyModel>(entityName: "MyModel")
let context = CoreDataManager.sharedInstance.queryContext //wrapper for persistentContainer.viewContext which is used to fetch the intended object to update
do
{
fetchRequest.predicate = NSPredicate(format: "recordId == %@", recordId)
let result = try context.fetch(fetchRequest)
guard let myModel = result.first
else
{
throw CoreDataCustomError.ObjectNotFound
}
myModel.data = data
try context.save() //works FINE!
//what DOES NOT work: try persistentContainer.newBackgroundContext().save()
//what DOES NOT work:
//persistentContainer.performBackgroundTask { (context) in
// context.save()
//}
}
catch let customErr as CoreDataCustomError
{
print("Object does not exist in DB: \(customErr)")
}
catch let err
{
print("Error saving data \(recordId): \(err)")
}
}
If I use newBackgroundContext() for fetch and save both (just in the below function, not in my UI), it works too. But I do not know if this is recommended approach
Yes, it is the correct approach.
When you initialise data in some context, you have to save it within the same context. If you try to save another context it will not work because this other context have no changes.
When you fetch some data using one context:
let result = try context.fetch(fetchRequest)
and then you modify it:
myModel.data = data
it is visible only in this context. Which means if you try to save another context it will not see the change to the model and your data will not be saved.