mirror of
https://github.com/yattee/yattee.git
synced 2026-11-04 10:57:18 +00:00
Re-fetch everything from iCloud when the local store was recreated
On tvOS SwiftData keeps the store in the app group's Library/Caches, which the system may purge. The CKSyncEngine tokens live in UserDefaults and survive, so the next launch opened an empty store and fetched only records changed since the old tokens; subscriptions and bookmarks that had not changed since never came back. DataManager now records whether the store file existed when the container opened, and the sync engine clears its persisted state once per launch when it did not, so the first sync after a loss is a full fetch. Also log the store path and a persistent-store failure that previously fell back to in-memory storage silently.
This commit is contained in:
@@ -160,6 +160,11 @@ final class CloudKitSyncEngine: @unchecked Sendable {
|
||||
|
||||
/// UserDefaults key for the record schema version this app last synced with.
|
||||
private let lastSchemaVersionKey = "cloudKitLastSchemaVersion"
|
||||
|
||||
/// A recreated store is answered once per launch; later engine setups in
|
||||
/// the same session (manual refresh, account change) start from the tokens
|
||||
/// that full fetch produced.
|
||||
private var storeLossHandled = false
|
||||
|
||||
/// Legacy UserDefaults key for pending save record names (pre state-driven
|
||||
/// engine). Only read once for migration, then removed.
|
||||
@@ -424,6 +429,7 @@ final class CloudKitSyncEngine: @unchecked Sendable {
|
||||
// re-delivered on a full fetch, so a schema upgrade must invalidate the
|
||||
// persisted state once to pick them up.
|
||||
invalidateSyncStateAfterSchemaUpgradeIfNeeded()
|
||||
invalidateSyncStateAfterStoreLossIfNeeded()
|
||||
|
||||
// Resume from persisted sync state so launches fetch only changes since
|
||||
// the last session instead of replaying the entire zone change history.
|
||||
@@ -592,6 +598,21 @@ final class CloudKitSyncEngine: @unchecked Sendable {
|
||||
UserDefaults.standard.set(Int(currentVersion), forKey: lastSchemaVersionKey)
|
||||
}
|
||||
|
||||
/// Clears persisted sync state when the local store was recreated from
|
||||
/// scratch while the tokens survived. The store lives in Library/Caches on
|
||||
/// tvOS, which the system may purge; the tokens live in UserDefaults and
|
||||
/// do not go with it. An incremental fetch against an empty store only
|
||||
/// brings back records changed since the tokens, so the first sync after
|
||||
/// a loss must be a full fetch.
|
||||
private func invalidateSyncStateAfterStoreLossIfNeeded() {
|
||||
guard !storeLossHandled, dataManager?.storeWasCreated == true else { return }
|
||||
storeLossHandled = true
|
||||
guard UserDefaults.standard.data(forKey: syncStateKey) != nil else { return }
|
||||
UserDefaults.standard.removeObject(forKey: syncStateKey)
|
||||
clearDeferredItems()
|
||||
LoggingService.shared.logCloudKit("Local store was recreated while sync state persisted, cleared sync state for full re-fetch")
|
||||
}
|
||||
|
||||
/// Loads persisted sync state from disk.
|
||||
private func loadSyncState() -> CKSyncEngine.State.Serialization? {
|
||||
guard let data = UserDefaults.standard.data(forKey: syncStateKey) else {
|
||||
|
||||
Reference in New Issue
Block a user