I have an app that's built entirely using SwiftUI. It uses NSPersistentCloudKitContainer to ensure that the iOS, watchOS and widgetKit targets all have the same fresh data.
The problem is, this works well when the target is in the foreground, but once any of them are in the background, those targets serve stale data. As soon as they're brought into the foreground, the data gets merged in and I see the correct data. I can tell that this is the case because I have a background task running and when I read from my entity in the background, it is always stale.
Because of this, my widget always shows stale data as well as my watch complications.
Here are my findings. iPhone App: Data is only fresh when active, if I try reading from the bg, data is stale
Watch App: Same as above
WidgetKit: The data is only fresh on launch
I don't think this is a bug, I think I'm just missing something in my implementation of Core Data. I know that there's Persistent History Tracking that might be a solution, but that seems overkill since the app can only be used by one person, I have many entities, and I'd expect that setting NSMergeByPropertyStoreTrumpMergePolicy would have solved that, which it does when the app is active.
Here's some code, my container
static let shared = PersistenceController()
let container: NSPersistentCloudKitContainer
init(inMemory: Bool = false) {
container = NSPersistentCloudKitContainer(name: "apoklisi")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
guard let description = container.persistentStoreDescriptions.first else {
fatalError("###\(#function): Failed to retrieve a persistent store description.")
}
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
		container.viewContext.automaticallyMergesChangesFromParent = true
		container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
}
}
This is used by all three targets.
Here's an example of the data being fetched manually in situations where I can't use @FetchRequest (say I'm in a background task or in the widget)
let fetchRequest = NSFetchRequest<Goal>(entityName: "Goal")				
fetchRequest.sortDescriptors = GoalRequest.getSortOrder()	
fetchRequest.predicate = GoalRequest.getPredicate(date: date)				
fetchRequest.shouldRefreshRefetchedObjects = true			
fetchRequest.returnsObjectsAsFaults = true				
return try! moc.fetch(fetchRequest)
My assumption is that I'm missing something that forces that remote data from being merged in and possibly something that clears the local cache?
Any help would be extremely helpful