Cloudkit CKRecordZoneNotification how to know whether Add or modify happened - ios

I am trying to implement Cloudkit sync with local cache (CoreData).
So far I managed to get the recordZone defined and get the relevant notifications. In the next step I check with CKFetchRecordChangesOperation what happened.
recordChangedBlock (i.e. according to Apple: ...for each record in the zone that changed since the previous fetch request....)
I do get the relevant record, but how do I know, whether this record was added or modified (without checking against my local cache)?
recordWithIDWasDeletedBlock I get the recordId, but how do I know which record it is in my local cache ? I could think of storing the recordId in the local cache in order to have a reference for such cases, but I can't believe that this is what I'm supposed to do...
Any suggestion is more than appreciated

There is no info in the recordChangedBlock that tells you whether it was added or changed. Keep in mind, even if it did, you still have to check whether the record exists or not in the local store. A record can be added into CloudKit and then changed several times all while your app isn't running. When your app finally runs, it will get only the last change notification. But the record doesn't exist in your local cache yet. So you must always see if you have the record locally or not and add/update accordingly.
With deletion, all you get is the CloudKit record id. Nothing else. What I do is ensure the CloudKit record id is based on the local key. This way I can easily find and remove the local record when the data is removed from Cloudkit. It also means that the local copy of the CloudKit data on all of the user's devices ends up with the same keys.

Related

cloudkit sync with local database

I save quite a bit of data to a mysql database on the phone, then upload when we have wifi. I am syncing about 6 tables and have it working properly, need to add more error checking, but it is working with some wait statements thrown in where I need them.
The problem is I am doing each update separately with a request and when the request comes back I don't have the information that I need to delete that entry from the local database, so that it doesn't re-upload duplicate information. Is there a way to save a variable to each upload so that when it comes back I can delete that entry? I can do that with one variable. It tells me the record I updated, but they are all referenced items to the owner and I can't find the info I need. I will be doing about 100 uploads at a time.

Are previousServerChangeToken for CKFetchNotificationChangesOperation user specific or database specific?

For public CloudKit databases, does anyone know if the data tokens used for previousServerChangeToken when initializing a CKFetchNotificationChangesOperation are:
1) User specific: a data token can only be used by one Apple ID
or
2) Database specific: the same token can be used by different Apple IDs to specify the same state in the CKNotifications database
I'm wondering because I have some preloaded local data that may need to be updated on first launch, and I'm not sure if I should use CKFetchNotificationChangesOperation (with an initial token saved in the main bundle) or just fetch all the records in the public database and check against the local data.
Notification change tokens are a per-user value and they can not be used to assume anything about the state of records in the public database.
It sounds like you're trying to use the public database to store files that update the default files in your application's bundle.
One way to do this would be to store a version property on all of your records of this type. When an app checks to see if it needs any updates it can run a CKQuery for all records with a higher version than what is saved locally. Your app can then download all of those records and use them instead of the data stored in its bundle.
What you need is CKFetchRecordChangesOperation, but this only works for non-default zones in the user private cloudkit database.
This operation will give you all the changes over the record zone, records deleted and updates (with only the changed attributes).

CKReference .DeleteSelf attribute has no effect

How does .DeleteSelf really work? Docs says:
When the reference object’s action is set to
CKReferenceActionDeleteSelf, the target of the reference—that is, the
record stored in the reference’s recordID property—becomes the owner
of the source record. Deleting the target (owner) record deletes all
its source records.
but my impression is that deleting a target will not always delete source. And it is quite annoying when it remains in the container, client downloads it, and expect that the reference point to somewhere, but target does not exist when building up slice of the server data store on client?
How do you treat this case? You ignore that sort of records? Or periodically you look up the CloudKit storage, searching for corrupt records to delete them?
Or instead of deleting a record is it better to set an attribute that it is in a deleted state, but keep it in the database?
I just struggled with this one for a while and I thought I would share my findings...
It is fundamentally a permission issue. The cascading delete will only work if the user deleting the records has 'write' permissions to all the records needing to be deleted.
So in the CloudKit Dashboard, the cascading delete will only work for the records created with the developer's iCloud account.
If you need to delete records that don't belong to the user deleting them, you can add 'write' permissions for a Record Type under Security.
If you are deleting via CloudKit Dashboard you have to wait before switching record types to check the other end of the reference. More than likely you switched before the delete actually happened. You can use Safari's Web Inspector on the Network tab to check when the delete has actually finished. It takes a very long time to delete multiple records.

Send local sqlite file to server

I have a database of many users,which i want to store on both locally and on my server.Whenever user updates any information,i successfully updates it in local database using core database. But how to change this information into the server?? I am not getting this please help?
I thinking of sqlite file to server every time user updates his information. but how to send data of sqlite file to server?
Add a column to your local DB that is the last time updated. (I think there may be a way to get SQLite to fill this in semi-automatically for you, but even doing it "manually" is no big deal.) Then, when you want to upload updates, query for rows updated since the last upload. Ship to the server as JSON records.
You can also keep a separate table that tracks updates, but that's for more complex scenarios.
You have to use some tactics for this. Here is a short explanation of this work.
Database Structure
Web service
You have to design database at local and server side and manage flag(Bool) and update time.
Like when you launch app then you have to check your local data and take last update date and send request to server what's new update after this date. If there is any update then you can send data as a result of that webservice and handle that response at local device.
When you do some changes at local device then you have to manage flag, update time and created date. flag will show it has update on server or not. If updated then Y otherwise N. And you have to send created and updated date with this.
During this request you have to manage in a same timezone. You can use standard UTC timezone because there may be chances that User can switch in different timezones so handle this.
If you need more clarification then you can ask at our chat room https://chat.stackoverflow.com/rooms/43424/coders-diary
This approach definitely work for you.

ABAddressbook notification of delete of Record

I use the kABpersonModificationDateProperty to detect AddressBook records that have been added/modified since the last startup.
Is it possible to detect which records have been deleted since my last startup?
I dearly wish it were so.
Your only option here is to cache all the record IDs, and then compare the full list at startup.
You're still exposed to situations where iOS rewrites all the IDs (such as when syncing via iCloud), in which case it will appear that all the records were deleted and an entirely new batch added. You can try to recognize cases where the ID was changed on an existing record by comparing fields (such as first/last name).

Resources