CloudKit subscriptions for public databases

I'm deliberating on whether to use CloudKit for an app that requires sharing data amongst self-created groups of users (for e.g. sharing company-wide directories). I would use a public database for this, but I had a couple of questions:

- if I create a subscription to listen to record changes for a partcular record type, will all the users get a notification when data changes, or only the logged-in iCloud user amongst his/her multiple devices? can there by 'group' notifications that cross iCloud users?

- if there's no way for a 'group' of users to get notifications, I guess polling from the app to CloudKit would work, with the groupID part of the predicate? Or is there another options?


Thanks.

Answered by PBK in 94462022

A more complete quote would be:


".......But all users in a group can individually create a subscription to.....changes in a single file in the public database. If that file is changed by any user then all users will get the notification."

So all users get the notification if all users create a subscription.

{But if one user creates a subscription UNDER A SPECIFIC iCLOUD ACCOUNT then all devices logged into that iCloud Account will get the notification. That usually is all of that user's devices. But it could also be the iPhone of that user's spouse or it might not be that user's iPad. Subscriptions and Notifications are based on iCloud Accounts not devices.}

My app, Carpooling: Princeton Ride Share, has a public database record type "Messages". All users subscribe to CKSubscriptionOptionsFiresOnRecordCreation using a predicateWithFormat:"ToNumber == %i",userIDNumber . Other users then create a CKRecord in Messages with a ToNumber equal to the userIDNumber of the user to whom they want to send a message. All user's subscriptions check that new record but because of their predicate, only that one user's devices get the notification. (That user then downloads the appropriate messages based on a query with the same predicate.) I think what you want to do is this, but instead of userIDNumber you will use groupIDNumber in the CKRecord and in the predicate.

(Background information - All users have access to all records in the ***** database.)


A subscription is created by an individual user who is logged into an iCloud Account. Notifications for that subscription go to all devices logged into that iCloud Account and only those devices. A 'group' subscription is not possible, to my knowledge. But all users in a group can individually create a subscription to, for example:


1) changes in a single file in the public database. If that file is changed by any user then all users will get the notification. In your case, each group would be associated with a single file and each user would subscribe to changes in that file and each user might make a change to that file.


2) changes in any file that have a 'GroupID' equal to the group's ID

Thanks. Some questions about this:

- "1) changes in a single file in the public database. If that file is changed by any user then all users will get the notification. " ... do you mean by changing a global object in the public database? Or through CKAsset? Because as far as I know, there isn't any way to access a file system using CloudKit (there might be with other iCloud APIs, but those aren't public).

- if you do mean a specific table that gets update with each update to the data (so that each user can get a notification), won't the notification only contain changes for the changed object (the global updated tabele? They won't see all the other changes from the database, right? For e.g. if I add a new record in the Contacts table and then update the Groups table associated with that user's 'Group', other users will only detect that the 'Groups' table changed, and not the fact that a new Contact record was added? I suppose one could query and reload the data at that point, which is better than polling, but just wanted to confirm.


Thanks for the help.

TMI.

By 'file' I meant CKRecord. Sorry.

There are three things happening here. 1) You save a subscription. 2) The conditions for that subscription are met. 3) Notifications are sent out.


1) Subscriptions are saved by any user of a device. That user is logged into an iCloud Account when they save a subscription The subscription is then a part of that iCloud Account.


2) The subscription specifies certain conditions by record type and predicate and what change must be made in such records. When these conditions are met the subscription generates notifications


3) Notifications are sent to all devices that are logged into that iCloud Account. Notifications can include pop ups on the screen if the app is not running and they can change the apps badge number. When an app is launched it can check its badge number and whether or not there are notifications pending for that iCloud Account. Notifications that are issued when an app is running will call to a method in the app.

Thanks; that was part of my original confusion. I was under the impression that if you change a record, you only get notifications for the same iCloud user on different devices, not ALL users in the app. Even if everyone has a subscription setup for that record type. So for e.g. the public database is just a list of Locations, and all users subscribe to new location records. If a user adds a new location CKRecord, would only that user get the notificaiton on his/her other devices ... or would everyone get the notification? You seem to imply the latter with this: "If that file is changed by any user then all users will get the notification."

Accepted Answer

A more complete quote would be:


".......But all users in a group can individually create a subscription to.....changes in a single file in the public database. If that file is changed by any user then all users will get the notification."

So all users get the notification if all users create a subscription.

{But if one user creates a subscription UNDER A SPECIFIC iCLOUD ACCOUNT then all devices logged into that iCloud Account will get the notification. That usually is all of that user's devices. But it could also be the iPhone of that user's spouse or it might not be that user's iPad. Subscriptions and Notifications are based on iCloud Accounts not devices.}

My app, Carpooling: Princeton Ride Share, has a public database record type "Messages". All users subscribe to CKSubscriptionOptionsFiresOnRecordCreation using a predicateWithFormat:"ToNumber == %i",userIDNumber . Other users then create a CKRecord in Messages with a ToNumber equal to the userIDNumber of the user to whom they want to send a message. All user's subscriptions check that new record but because of their predicate, only that one user's devices get the notification. (That user then downloads the appropriate messages based on a query with the same predicate.) I think what you want to do is this, but instead of userIDNumber you will use groupIDNumber in the CKRecord and in the predicate.

Thanks for the great and helpful answer.


A couple of related questions for you, if you have the time:

- do you find CloudKit pretty reliable as a whole? I've used "Core Data with iCloud" in the past, and regret it massively, so don't want to fall into the same trap again

- do you use Core Data as the backing store for your CloudKit app? If so, do you use NSIncrementalStore with it?


Would be great to know your answers.

Thanks.

I don't use core data. I have found CloudKit to work reliably and quite fast. Once I figured out that it was responding to iCloud Accounts not to devices I also found it pretty intuitive.

The GROUPID field in CKRecord is a good idea. But let us say I have Location CKRecord in my public database create with group ID for my group ID "123456". My question - How do I distribute "123456" programmatically to others in my group, so that when they create their Location CKrecord they can use my group ID "123456". Unless they create the Location CKRecord with my group ID my subscription wont get their records correct? The reason I ask is because - some other user may want to create his/her own group using my app with some other GROUP ID let us say "654321". How does my app take "654321" and share it with his/her contacts which are completely different from my contacts with whom I want to share my GROUP ID "123456", all programatically shared and used in the app while creating Location CKRecord?

CloudKit subscriptions for public databases
 
 
Q