iOS: CKFetchNotificationChangesOperation results incomplete
Asked Answered
Y

1

6

I'm building an iOS app that heavily relies in CloudKit as a data source.

After installing the app and running it for the first time, I need to download a great amount of data that resides in the public database of my CloudKit Container. I do this with the CKFetchNotificationChangesOperation

This operation runs every time I launch the app to check for data changes since the last server change token I received. Obviously, on the first launch of the app, the change token I have to provide is nil, which would cause the CKFetchNotificationChangesOperation to load ALL changes ever occurred on the database.

The data that is then returned will be stored locally as my desire is to have a local cache of all data relevant for my user. I store this data in a Core Data Database. As the data set the app needs when first launching might be big, I really need CKFetchNotificationChangesOperation to fetch ALL Changes on the server.\

This however, seems unreliable. When testing this service with some data I entered in my database, I don't receive all data I'm supposed to receive. As I enter more data in my public database, the CKFetchNotificationChangesOperation seems to completely ignore the records that I entered before. Sometimes, some slip through but it is very unreliable.

Obviously, I have verified that my subscriptions are legit (the same records got loaded before), and I have checked whether the moreComing parameter of the CKFetchNotificationChangesOperation is true (It is always false)

Question

What should I do to get ALL data in my public database on an initial load? I thought that CKFetchNotificationChangesOperation was supposed to do the job, but it seems unreliable. Is there anything like a 'scope' that I can configure on this operation to force it to load all my data? Or is CKFetchNotificationChangesOperation not fit for initial loads and should I just load all data I need through custom operations?

Yardstick answered 31/8, 2017 at 12:50 Comment(0)
A
3

Based on what I've found regarding the notification messages, it seems that the problem could be stemming from one, maybe both, of two possibilities:

  • Records are being stored asynchronously, providing an unintended delay when populating local datasets.
  • Read notifications are muddling the desired query/subscription results.

Both situations can be fixed using a local storage (array or dictionary) of the records and their metadata. As described in Maintaining a Local Cache of CloudKit documentation by Apple.

Situation 1:

Having locally stored records will allow you to populate your initial dataset, along with making any updates to changes, while waiting for any asynchronous delays through CloudKit to be finalized.

Situation 2:

Have a local array of every NEW notificationID that has been seen. As described in this StackQuestion Q&A, the readNotifications seem to be the reoccurring problem. Marking a notification as read prevents the notification from returning in future fetches, but they can cause issues until the CloudKit database is updated.

~~~~~~~~~~~~~~~~~~~~~~~~~ Linked Solution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

THIS is a Stack Overflow question and answer that includes the code used to resolve a similar issue, although it does not include details as to how/why it worked. So, checkout this, one of the previous linked Q&As, that goes into a little more detail if needed.

Let me know if you have any questions, and/or want any clarification.

•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••

••• WWDC CloudKit Best Practices (starting around 12:45 into the vid)

Adelaideadelaja answered 2/9, 2017 at 18:25 Comment(5)
Thank you for your answer! I have updated my question as I realize I left something important out. I do have the desire to maintain a local cache of the data that is downloaded. My problem occurs only when first launching the app, when no data is locally cached yet: The notifications I get from changes at incomplete. It seems that there is some kind of 'scope' to the CKFetchNotificationChangesOperation, as it reliably loads new record and misses old records. I am in doubt now: Should I write an operation that just downloads ALL data I want regardless of changes? Or keep doing it this way?Yardstick
You're welcome. Have you tried storing all the notificationIDs you've accessed to the device (maybe pList) you can then cross reference your list with the records from CloudKit?Adelaideadelaja
I'm not sure that will solve the problem. I know for a fact that all subscriptions work, as the notifications that do not come in now did come in before. This is what confuses me so badly, and gives me the impression that there is some kind of scope on the subscription.Yardstick
Are you familiar with how CloudKit's database utilizes zones? After rewatching the WWDC CloudKit Best Practices, I am relatively certain that the "scope" you keep referencing is actually the specific zones: private, public, shared and even custom. I've updated my answer with the WWDC link & time the CK team discusses themAdelaideadelaja
Yes, I am familiar with zones and I know for a fact that this problem is not caused by them as I store all my test records in one zone. I keep referring to a scope because it seems that I only get notifications up to a certain point in time, or up to a certain amount. This would not make sense either as my moreComing parameter is false. For now, I built a workaround that just downloads all initial data and from that point on relies on notifications, which works fine. However, that still does not solve the central problem: Why do I get incomplete notifications with a false MoreComing parameter?Yardstick

© 2022 - 2024 — McMap. All rights reserved.