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.
Here's some code, my container
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)
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
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
Here's some code, my container
Code Block struct PersistenceController { 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)
Code Block 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