Understand a little bit more about the Apple’s cloud — Guideline
Today even the small application need store some information. Unfortunately, when we want create an application we know how expensive an application can be. We have to develop the design of the screens, the logic of the application and sometimes the server. Create a server and deployed on Amazon or Azure sometimes can be very expensive, when we just need to build an minimum value product and see if our ideia is right.
Cloudkit cames with a good solution when we need to build a quickly solution and validate your idea without spend one single buck. Of course, CloudKit can be use if your application became a huge success as well.
In this article, I will relate all my experience with the framework, all my understand how the framework works. Things that I liked and things I don’t like, the problems I faced and how do I fix them.
What is CloudKit ?
Cloudkit is a transport technology that provides access to the apple server where all the information create by your users throught the app is storage. So every time the user save, update, fetch or delete some information the Cloudkit intercede and make all the communication with the apple servers.
How do we start an application with CloudKit?
We can start an application in cloudkit through http://developer.apple.com, in the left column you go to the section "certificates and profiles" then to the section "iCloud container". The picture in the bottom shows the place where you can create a identifier which is going to be our container.
The identifier is going to our container. The container identifier should have be prefixed with the word "iCloud" follow by your bundleId, for instance, "iCloud.com.kobe.TDC".
Enable Cloudkit Capability
To enable Cloudkit in our application we need to go to XCode in the project on the capabilities section and enable. The picture below show the right place where we have to do this configuration.
When you enable iCloud section check if you mark the Cloudkit section and select the container identifier you create on http://developer.apple.com
The dashboard is the place where you manage all your database structure. You can create schemes, record, subscription and also manage who can change any kind of information related with other data in the server.
You can access the dashbord throug the developer.apple or the XCode on the section capabilites showing in the picture above.
The section record type is the place where you can create our table and the attributes(Field Name) that your table will have. For example, in this article, I will create two tables Attendee and Section. The picture in the bottom show these table created and some attributes configured with our field type
The roles section is the place where you can create new roles. For example, if you just want a specific user has the ability to delete you can add a role to that schema. In the picture below we can see the creation of a new role.
The subcription section show all the subscription that the users register. The subscription is one of the great features of the framework. The subscription allow us to inform the user that something happens in the database. For instance, Let’s imagine that we have a record session and we change the schedule of the session. If the user registered in the subscription, the cloudkit send to the user a notification with a custom message provide for us developers, informing that change happened in the database.
The user records is the section where you can see all the users that use your app. In the picture below, we are not able to see more information about the user, actually we don't see any information, because your application need to ask to user to get more information such as name and email address. If you don’t ask we only know that a user uses your app. Apple takes the privacy of the user very serious. This information that your app request is related with the iCloud account.
The default zone is the section where you can see all the record created by the community that uses your application. In this section you can create, update and also delete records.
The usage section allow us to check how many users, requests, asset storage and also other statistics to control if the application need more resource. For example, if we are getting more than 100 request per second, we need to talk to apple to get more resources.
Now we are going to check how we can access all this data through our iOS application. How in our app we can save, delete, update and perform complex operation on your application.
The container is the identifier where the cloudkit can find our application in the apple servers. We created it the developer.apple.com before. Each application have one container.
In the code above, we can see how we can get the container from cloudkit.
Every app access at least one container and each container contain two database one public and other private.
As you can see in the above we have two database. Every client has your private database which is your iCloud account. As I told before you are not able to see the private data, the only one can access this data is the user. Once the user allow us to store information in the private database, be careful with this space, because we are using the store from user's iCloud account. So for us developer we see the database as the picture below.
To access the public or the private database we can get this throught the container. In the below I list some rules about the databases what are allow in each one.
The record is the data itself. You can think this as a row in a table. The records live inside of the database.
A record is a structured data. It is similar as a NSDictionary where we have keys that is the field name that we create when we make the scheme and a value that is the type related with. The type of the values are those ones we are used such as plist types and also a new ones like CKAsset and CKReferences.
So how do you can create a record.
Pretty easy!!!! Well you may wondering I can subclass the CKRecord and do something like this:
Not really. The apple documentation says:
So what can we do? I am using this approach, we receive in the constructor a CKRecord and we use this reference and in our class we update the record every time we change the variable.
Just one more warning that is in the apple docs
So be careful with the size on your CKRecord.
The reference is the way we connect the record so one session has one or more attendees.
This make sense however cloudkit works with back references so the picture above is wrong and the right one is like this:
The Attendee holds the reference to the session and we create a reference like as the code below.
The parameter action in the constructor of the CKReference is to perform cascade delete if you pass the parameter .DeleteSelf, that means if we remove the parent the sons will be remove as well.
The CKAsset is the class represents large unstructured data and is owned by the CKRecord. So if we delete the CKRecord we loose the the CKAsset. The CKAssets is not store in the database. They are storage in a bulk store, but for us as developers this is transparent.
So let's imagine the user take a picture from the camera and we want send this image to the server. To achieve this we need to do something like in the code below.
We need store the image first. Pretty weird, right? It's necessary because cloudkit is smart enough to know if the user has the image. So if the user has the image, the cloudkit don't download again the image from the serve to save bandwidth.
The login is a little different than we are used to. We don't perform a login like filled with your email and password. The user login in your application trought iCloud account, it means that if the user is login iCloud account on the device, the cloudkit automatically add the user to the table User Records, but remember it not show the user's info.
To check if the user is log in iCloud account on the device we have to use this method below
Once we don't have a login screen we can let the user uses your app until we need it. When the user needs to create an record, for example, and the users don't have connect to an iCloud account we can to redirect the user to perform a login in iCloud account. The example below uses this aproach.
The convenience API is an easy way to start perform save action with record such as save or update. The convenience API is a extension from CKDatabase as you can check below.
To save an record with the convinience API is very easy.
As you can see all the methods from cloudkit are asynchrouns and for all of them we need to create a beautiful error handling as apple suggests. Of course we need to check the error because this is the diference between a funcional and not funtional app.
The convenience API is a good way to start as I said, but what happends if we need to get an object, get other object from a reference and update its value. We need to perform three request at least. Probably we get a code like this.
As we can see this code is a mess. One thing that we can use is NSOperation to save us. For our luck the cloudkit have a lot NSOperation called CKOperation. Cloudkit was built with a lot operation to avoid situation like that. In the example below we catch all the attendees from a session using CKOperations
In the code above, we create a operation to retrieve a session, when this operation is completed we start a new operation to retrieve all the attendees of the session. In the end of the code, we made the second operation depends from the first. We need to do this because if the first one fails we shouldn't call the second. The last but not the least we have to create a NSOperationQueue and add to it the CKOperation we have create it.
The CKQuery class is used when we want to get a slice from the database. To use this class we have to understand first the NSPredicate. The CKQuery uses a subset of NSPredicate to inform cloudkit which information to get, as you can see in the example above. Here we have a few rules, but we have a lot more, please check: NSPredicate Rules.
Now image we want to retrieve some information, but we don't want get all information at once. We wanto to performa a pagination. This is a little bit trick how we do it in cloudkit
To create a pagination we need to instantiate a CKQueryOperation with a query that we want to perform. We have to catch a closure in the queryCompletionBlock, if we have more results to retrieve this closure will return a CKQueryCursor and in the future we need instantiate again your CKQueryOperation but this time we have to instantiate with the cursor. The class above do this kind of operation.
The Cloudkit is a great tool if you want just validate an idea or use in production mode. I believe the framework needs to greatly improve and it will, because It's necessary for us, developers, this kind of tool because we can spend more time in your apps and not doing the backend.
Here is my first step using the framework. I am writing this to help others that have difficulty to understand the framework and how to use it. I know we have a lot material here, but cloudkit have a lot to cover yet, but it's too big the article so far!!!! Thanks.