How To Integrate Cloudkit In A Cocoa Application
In 2014, alongside iOS 8 and macOS Yosemite, Apple unveiled CloudKit, a framework that enables developers to directly interact with the company's iCloud servers. Before the introduction of CloudKit, developers could interact with iCloud through three APIs:
- Key-Value Storage
- Document Storage
- Core Data Integration
These APIs continue to exist alongside CloudKit. Not every application needs direct access to Apple's iCloud servers and the company emphasizes that these APIs are in no way deprecated.
If your application needs more control over the data that is stored in iCloud, then CloudKit is the unequivocal answer. CloudKit is more powerful than any of the aforementioned APIs, giving the developer fine-grained control over the data stored on Apple's iCloud servers.
Even though there is some terminology you need to become familiar with, getting started with CloudKit is surprisingly easy. Setting up a project for CloudKit is straightforward and making queries is easy to pick up with CloudKit's convenience API.
That said, most developers run into the same obstacle, how to integrate CloudKit in an application. I am not referring to the setup process or getting up to speed with the framework. The following quote from Designing for CloudKit is telling.
[The] CloudKit framework should not be used to replace model objects in your app and should not be used for storing objects locally. It is a service for moving data to and from iCloud and sharing data between users of your app. - Designing for CloudKit
CloudKit is nothing more than a framework for interacting with Apple's iCloud servers. Your application is in charge of creating a model layer that interacts with CloudKit. If your application needs to be functional without a network connection, then that too is a responsibility of your application.
What happens if the user's device loses its network connection? How does your application respond to such an event? CloudKit is a application programming interface. It is not a persistence layer.
If your application needs to remain functional when the user's device is offline, then that is something you need to implement. And that is where the rubber hits the road for most developers. How do you do this? What should your application cache or store locally? When and how should it do that?
There is no single answer to these questions. And that is a good thing because it means that the CloudKit framework is flexible and focused on one thing, moving data from and to Apple's iCloud servers. In this article, I briefly discuss how an application can deal with the above problems.
It is possible to develop an application that relies solely on CloudKit. This means that your application isn't functional if the device doesn't have a network connection. The user experience of such applications significantly degrades if the network connection is flaky or unreliable. A surprising number of applications require a network connection to be functional. Social network applications, such as Twitter clients, come to mind.
Even if your application doesn't cache or store the data it fetches from iCloud, it is recommended to create a model layer that consumes the data CloudKit hands your application. This makes it easier to cope with future changes of the CloudKit framework and it makes working with the data much easier.
Every application that interacts with CloudKit has a container that represents the iCloud storage of the application. That container contains a public database and many private databases. Each private database maps to a user of your application.
If you are creating a task manager, such as Things, then the user's tasks are stored in the private database that is linked to their iCloud account. The public database is used for storing data that is accessible to every user of the application. This is important for the rest of our discussion.
What you store or cache locally depends on the goal of your application. If you are developing a recipes application, for example, the user expects its recipes to be available at all times, including when their device is offline. That means that your application needs to cache the recipes that are stored in the user's private database.
In such a scenario, iCloud acts as a backup or synchronization service. The data that is stored locally is more important than what is stored in iCloud. The user experience should not deteriorate if the device goes offline. For this type of application, iCloud only offers benefits to the user. Benefits that are mostly invisible to the user.
In Samsara, I plan to use CloudKit to synchronize the user's meditation profiles across devices. If the device is offline, a common scenario during meditation, the user experience doesn't change. Samsara's iCloud integration only offers benefits and those benefits are mostly under the hood.
The type of application mostly determines its relation with iCloud. Applications focused on sharing data, for example, most likely benefit from a cloud first approach. If such an application uses CloudKit as its backend, then that means it stores large numbers of records in the public database. Keep in mind that this is a generalization. Every application has its own user stories and goals.
If the public database of an application holds a large number of records, then it isn't realistic to keep a local copy of every record or cache the contents of the public database. Merge conflicts and users running out of disk space will give you nightmares.
That doesn't mean that there isn't a middle road, though. It is possible to adopt a caching strategy to improve performance and keep the application functional if the device is offline. For such applications, it can be interesting to keep the current application state in memory to ensure the user can still use the application.
There's no need to show the user an alert if a Twitter client can no longer reach Twitter's API. The user won't be able to fetch new tweets, but they can still browse the ones that are cached or stored in memory.
Not every application can be put in one of the above categories, but that isn't important. This discussion is more than an architectural discussion. It is as much about usability as it is about how to integrate CloudKit in an application.
This discussion is more than an architectural discussion. It is as much about usability as it is about how to integrate CloudKit in an application.
Remember the questions I asked earlier. What happens if the user's device loses its network connection? How does your application respond to such an event? Is the application still functional?
If you started reading this article with the goal of finding a clear solution to your problem, then I probably disappointed you. However, I hope you now have a better idea of what CloudKit is and isn't. If you treat CloudKit as nothing more than an API, then finding a solution that fits your application's needs should be less daunting and less confusing.
Questions? Leave them in the comments below or reach out to me on Twitter.