This is the third part of a trilogy of posts about Apple’s CloudKit. In the first part, I showed you how to manage critical data. The second part was about updating a large amount of data on Cloud Kit. And in this third part, we will learn how to use subscriptions so that we will be notified when the data changes in CloudKit.

CKSubscription

I introduced subscriptions in this post. With subscriptions you can track changes as they are occurring on the server.

Each time a change occurs, a remote push notification will be sent to the device. This notification includes the recordID of the changed record together with the database (public or private) and the reason that the push notification was trigged. There are three possible reasons that could have triggered the notification: a record has changed, a new record has been added, or an existing record has been deleted. When you create a subscription you have to specify which record type you want to track and the reason (creation, deletion or change).

This is an example of how you would create a subscription in Swift:

In Objective-C:

Once your App successfully saves a subscription, there is no need to subscribe again. In fact, if you try to save the same subscription again, you will receive an error from CloudKit. From now on, you only have to process the push notifications when they arrive and take the pertinent action based on the reason of the change.

You need to register to push notifications in the application:didFinishLaunchingWithOptions: method of your App’s delegate.

In Swift:

In Objective-C:

Then, implement this method of the AppDelegate to handle the push notifications.

In Swift:

In Objective-C:

The above code is quite self explanatory. First we check if we are receiving a CKQueryNotification. If so, we identify the reason that triggered the notification. If a record has been deleted, we delete our local copy of the data. If the other two cases, first, we fetch the updated data from the server, and then we modify or create a new object, depending on the reason.

As you can see, everything till now seems quite simple. But at this point, you should already be asking yourself, what will happen if the App does not receive the push notification? And indeed, there is no guarantee that the push notification will be delivered. The device could be in airplane mode when lots of records get changed on the server. What is going to happen when the device is online again? Will it receive all the notifications triggered or only the last one, because push notifications are coalesced?

The answer is that the device will only receive the last notification. So how can the App be informed of all the changes that had occurred while it was unavailable? Fortunately, CloudKit covers this scenario with the CKFetchNotificationChangesOperation.

When your App launches, or becomes active, or it receives a push notification, it should first check with CloudKit if there are CKNotification objects pending to be processed. These are notifications that were not delivered to the App, because of different reasons, and we want to retrieve and process them.

Create a CKFetchNotificationChangesOperation operation and assign it a block to its notificationChangedBlock property. This block will be executed once for each notification. In this block, perform the operations with your data depending on the reason that triggered the notification (create, update or delete).

For each notification processed, save its notificationId property in an array. Then, in the fetchNotificationChangesCompletionBlock property, assign a block that will be executed at the end of the operation, when all the notifications are processed. If no error is fired, we will create another type of operation. This time we will use a CKMarkNotificationsReadOperation and we will pass in its initialization the array of notification ids that we have processed. This allows us to mark these notifications as read in the server, so the next time we ask for the notifications, they will not be served again.

In Swift:

In Objective-C:

Take note that when the fetchNotificationChangesCompletionBlock, there is the possibility that not all of the notifications pending to be processed have been served in this operation. This is due to the limits in size and records of the amount of data that a CloudKit petition can serve. If this is the case, the operation moreComing property will be true. You should then start a new CKFetchNotificationChangesOperation passing to it the CKServerChangeToken received in the block.

Conclusion

Thanks for reading this series of CloudKit tutorials. Remember to also take a look at the first and second part. I encourage you to continue investigating CloudKit, and using it to build powerful Apps for Apple devices. To learn more, go to https://developer.apple.com/icloud where you will find lots of excellent resources.

Keep Coding!!!

Vicente Vicens

iOS Consulting | INVASIVECODE

iOS Training | INVASIVECODE