3

I've been reading about and trying to use the CKSubscription feature for weeks, but I can't find info about some general questions. I've read Apple docs, online tutorials, books I bought, and questions here on SO, but I still don't understand the fundamentals I think. Any help is very much appreciated.

Here are questions I cannot find answers to:

1). What is the purpose of the subscriptionID? The convenience init does not include it, so why is it needed in the designated init? If you use it, is it the same for all users of the app?

2). I saw someone mention here that you can unregister a subscriptionID. Why or how would you do this?

3). Can subscriptions be setup in both public or the user's private database?

4). If I have a query based subscription that is the same for all users, will there only ever be 1 subscription listed in the database?

For instance, I'm having trouble getting notifications to work with my specific use case. It's not a problem in my setup, as I can get a True predicate to work and the notification comes. So I must not understand the fundamentals of how subscriptions work still.

I'm trying to setup a subscription that fires whenever a new record is created when a different user makes a comment on a post. This new record will then contain a reference to the user who created the post. The only subscription I see in the database for both users is - Notifications.user (equals reference). So, I'm assuming I'll only ever see this one subscription.(?) But how does the server keep track of every user's recordID or know when to send it to a specific device?

The problem is I can't get the notification to work. I manually add a record in the dashboard, and I put the other user's recordID as the CKReference. While I'm adding the record, I have the app running in the background on a device under the user's account whom I added as the CKReference in the field. I'd expect the query to trigger and send a push notification since someone commented on this user's post.

Here's my code to setup the subscription:

func subscribe(userID: CKRecordID) {


    let options = CKSubscriptionOptions.FiresOnRecordCreation

    let userRef = CKReference(recordID: userID, action: .DeleteSelf)
    let predicate = NSPredicate(format: "userRef == %@", userRef)
    let predicateTwo = NSPredicate(format: "read = %@", "")
    let compoundPred = NSCompoundPredicate(type: .AndPredicateType, subpredicates: [predicate, predicateTwo])

    let subscription = CKSubscription(recordType: "Notifications", predicate: compoundPred, subscriptionID: subscriptionID,
        options: options)
    subscription.notificationInfo = CKNotificationInfo()
    subscription.notificationInfo.desiredKeys = ["userPost"]
    subscription.notificationInfo.alertBody = "Someone replied to your Pod post"

    publicDB.saveSubscription(subscription, completionHandler: {

        subscription, error in

        if (error != nil) {

            println("error subscribing: \(error)")

        } else {

            println("subscribed!")

        }

    })
}
Renee Olson
  • 267
  • 1
  • 15

1 Answers1

1

Let me try and answer:

  1. SubscriptionId allows you to identify later a subscription for example to delete it using the CKDatabase method deleteSubscriptionWithID
  2. For how see answer 1. As to why, well maybe you do not want to get notifications on this subscription any more. This depends on what you are trying to achieve with your app.
  3. Yes
  4. Yes, if you register only one subscription it should work for all users of your app

Regarding your issues, please note that a user recordIDs are special, so you may have issues specifically related to that due to the privacy issues around them. I would suggest to try a simple case that does not involve users and see if subscriptions are working for you. Then think again about how you use user record IDs

farktronix
  • 3,880
  • 1
  • 21
  • 27
harryhorn
  • 892
  • 6
  • 8
  • Thanks @harryhorn. I was able to get a simple true predicate to work and received the push notification. Also, I'm able to do similar predicates for the user's recordID in my app, like when I want to pull the current user's posts. And my subscription predicate is basically the same, so wondering if there's something about references and subscriptions that don't work...although I saw someone else do something similar with a reference on SO, but couldn't tell if was a user recordID. And I can't find any other examples of someone doing what I'm doing for subscriptions. Appreciate your help. – Renee Olson May 08 '15 at 17:47
  • Please explain what exactly you are doing with the references and what are you trying to subscribe to so I can try and help. – harryhorn May 09 '15 at 18:59
  • Thanks @harryhorn. When a user makes a comment on another user's post, I create two new records-a comment & a notification record. In the notification record, I have three fields, one with a reference to the user who created the post, one w/ a reference to the post, & one that marks it as read (for inside the app's notification section). I want a query subscription to let me send a push notification to the user when one of these notification records is created (someone replied to their post) & when it has not been marked as read already. Pasted my code above to show u how I do it now. – Renee Olson May 09 '15 at 20:42
  • It seems the issue is with this code: `let userRef = CKReference(recordID: userID, action: .DeleteSelf) let predicate = NSPredicate(format: "userRef == %@", userRef)` where you bind the predicate to a SPECIFIC user reference. That seems wrong to me. Are you sure this is needed? perhaps you should get notifications and then decide in the client if the notification is interesting or not? Another option is to change the predicate to test an ID (like a userID) and not compare to a reference object. – harryhorn May 10 '15 at 16:27
  • Hi @harryhorn. I've been using predicates with a reference to the user for other queries & it works. I grab the user's recordID and store it in NSUserDefaults and then I query for any posts/comments made by the user via a reference to them. For push notifications, it only makes sense for the current user if someone replies to their post. Otherwise they'd get notifications for all user's post. I tried something similar to what you suggest, where I changed the field to a string with the user's ID, but the subscription fails. Thanks for trying to help! I'm at a loss. – Renee Olson May 11 '15 at 03:32
  • Hi Renee. OK now I understand. Good to know this kind of predicate with reference works in general. Two things I would look at: 1. the line `let predicateTwo = NSPredicate(format: "read = %@", "")` why are you comparing read to an empty string. Should this not be a boolean? 2. The code does not show where subscriptionID is defined. Since you are going to create multiple subscriptions like this (per each user for his posts) shouldn't they have different IDs or not use IDs at all? Hope this helps. Harry – harryhorn May 12 '15 at 05:31
  • That code I got from a book that did the subscriptionID that way, which is why I asked what's the purpose of the subscriptionID. I mark read as true if they view a notification inside the app, so I'm also wanting the records that have a blank read field for the push notifications. But my other question 4 asks about having only one subscription for all users, because that is all I see in the dashboard - Notifications.user (equals reference). My un-answered post -http://stackoverflow.com/questions/29786016/cloudkit-subscription-notification-for-ckreference-not-working-as-expected – Renee Olson May 12 '15 at 17:20
  • Also in that link I sent above, I setup the subscription slightly different from another example I found which uses the convenience API and leaves out the subscriptionID. And it was on a blank app and new container, just to see if I could get it to work. Thanks @harryhorn. – Renee Olson May 12 '15 at 17:35
  • Thanks for your answer but I'm still not clear if the subscriptionID needs to be unique for each user or not? – malhal Mar 30 '16 at 17:01