ggruen / CloudKitSyncMonitor

Monitor current state of NSPersistentCloudKitContainer sync
MIT License
486 stars 44 forks source link

Not catching key errors #33

Open bnulman opened 1 month ago

bnulman commented 1 month ago

Trying to incorporate this into an app I'm working on.

If I turn off iCloud for my app in iCloud settings while the app is running, the status will show as broken, though the error is "Import is broken", rather than "accountNotAvailable". However, if I force quit the app and launch it again, or if I disable iCloud prior to app launch, the status will always show as a gray cloud/"notStarted". In the console, I can see that the error is "Unable to initialize without an iCloud account (CKAccountStatusNoAccount)", but CloudSyncMonitor is not catching that.

Another problem is that it is reporting that sync has completed when actually the sync has only started and is still in progress. This is particularly an issue for large syncs that can take a while because the user thinks the sync is complete but none of their data has appeared.

ggruen commented 1 month ago

Hi @bnulman ,

Are you using version 3.0.0, which we just released yesterday? It has a bunch of changes, which may or may not improve the situation. If not, I'd recommend updating (see the newly updated README, which also has a lot of changes, for instructions).

One of the issues addressed in version 3.0.0 is that you need to call SyncMonitor.default.startMonitoring() as early as possible in your app's lifecycle so that SyncMonitor can subscribe to notifications from NSPersistentCloudKitContainer before it (NSPersistentCloudKitContainer) starts sending notifications. It sounds like SyncMonitor may be missing some notifications, causing it to report funky statuses for you.

That said, there are some nuances to NSPersistentCloudKitContainer that one needs to be aware of, and the primary one is that core to its design philosophy is that there is no such thing as "sync is finished" (one of Apple's senior developers made a comment to that point on developers.apple.com soon after NSPersistentCloudKitContainer's release). As such, NSPersistentCloudKitContainer's definition of "in progress" may not be what the average user (or developer) expects.

TL;DR:

In particular, NSPersistentCloudKitContainer sends a notification when an import or export starts, and another when it ends. If it hasn't, in its opinion, decided that it has started an import or export, then the sync isn't "in progress", even if the data on iCloud doesn't match the data on the user's device yet. You can see how SyncMonitor translates NSPersistentCloudKitContainer's notifications into statuses in the processSyncEvent method (currently in Sources/CloudKitSyncMonitor/SyncMonitor.swift at line 424).

bnulman commented 4 weeks ago

Yes, this was with v3.0.0, and yes, I called SyncMonitor.default.startMonitoring() as early as possible.

Regarding the 2nd issue (inaccurate reporting of sync completion), I believe the problem is that there are often multiple Import (for example) operations happening simultaneously, but CloudKitSyncMonitor will report that sync is completed when the 1st operation finishes, rather than making sure that all the started operations have finished.

I solved this issue for my use case by keeping track of how many Import operations started and how many completed. Until those two numbers match, it reports that sync is in progress.

ggruen commented 1 week ago

Hmm, if NSPersistentCloudKitContainer is essentially sending nested notifications, then SyncMonitor isn't designed to handle that. If you made the workarounds within CloudKitSyncMonitor, could you submit a pull request?