Data Persistence — CloudKit
Using CloudKit to save data to iCloud and retrieve it on other devices
My last piece was about using
NSUbiquitousKeyValueStore to save key-value pairs to iCloud. Well, now it’s time to break out the big guns! Today, we’ll be using CloudKit to create, retrieve, update and delete (C.R.U.D.) data from iCloud.
I would love to do a multi-part series on using everything that CloudKit has to offer, such as C.R.U.D., subscriptions, notifications, and other things along those lines, so I have started here with the easiest (in my opinion) and that is C.R.U.D.
Using CloudKit, even apart from the
NSUbiquitousKeyValueStore, is a little more intense than just saving a key-value pair.
So let’s set out a little roadmap of what I want to cover in this piece:
- The Interface
- CloudKit Dashboard
- Saving Records
- Retrieving Records
- Updating Records
- Deleting Records
- General Notes
What Is CloudKit and How Is It Useful?
CloudKit, at least in my opinion, is a data persistence layer that can really put your app over-the-top. It can give the user a sense of being so connected that they will be poised to continue using your app for the convenience alone. It’s a great feeling when a user is able to start something on their iPhone and then continue it on their iPad or Mac.
Most importantly, it provides the user with the ability to save more complex data than just key-value pairs, which comes in handy when a developer wants to make an even more complex app.
Getting started with CloudKit can be a bit tricky but I’ll be with you every step of the way. If you find the way I describe it difficult to understand, then I suggest heading over to the Apple Developer Documentation on CloudKit.
- Xcode 10
- Swift 4 (and up)
- Apple Developer Account ($99 / year)
I am going to assume the reader is new to CloudKit because it was such a confusing thing for me to understand at first. However, once you work with it long enough and start to piece things together then it will start to click.
The first thing to do, as always, is to create a new Xcode project. We will select a
Single View App for this tutorial (the completed project can be found at the end of this article).
Next, name it whatever you want, for this project I will be naming it
Click next and save it somewhere where you’ll remember. Now let’s set up some simple capabilities in your app so we can get the CloudKit functionality within it.
Click your app name at the top of the
Navigator and choose the
Capabilities tab at the top. After that, find the iCloud option in the list of capabilities and turn the switch on. Make sure
Use default container are selected. Once those three things are done your app is ready to use CloudKit!
The last thing we’ll need to do, it’s something I like to do to stay organized, is to make a
Variables.swift file so that we have all the variables we’ll need in one place.
To do this, press
Swift File, name it
Variables and you should be good to go!
This is what my final
Variables.swift file looks like:
- Line 2. Importing CloudKit will let me use some of its framework for a variable we’ll define later
- Line 4. This is an array of
Stringsthat when we retrieve all of our records, all of the titles will go into this variable as multiple strings
- Line 5. This is an array of
CKRecord IDs, for every record you save, iCloud will assign it an ID. When retrieving the records we will put all the IDs into this array
As with all my articles, I want the UI to be as simple as can be so you can see and understand the relationship between the code and the interface. By making it as simple as possible, it opens you up to understanding that you can connect the code we write here to any type of IBOutlet, IBAction or even a timer, which will help you when creating an app to give you a bit more freedom than you may think when reading a normal tutorial.
In UI I have set up, I added a
text field and 4 buttons. Each button will have its own action for
Next, we need to connect the interface to the code. In order to do this, go into the assistant editor by holding down
Command-Alt-Enter , control-click the text field, drag it over to
ViewController.swift, and release. You have made a
IBOutlet — name it whatever you want and do the same for the buttons.
control-click the button and drag it over to
ViewController.swift , releasing when your cursor is under the
ViewDidLoad method. Mine ended up looking like this:
If you need more help making IBActions or IBOutlets, check out this YouTube video for more information.
In order for you to save data to iCloud, some things have to be set up first. Some of the things I am going to show you are automatically set up when you go to save a record but I would much rather set up everything in the
iCloud Dashboard beforehand so we know that everything works.
First thing you’ll want to do is go to the developer dashboard where your
iCloud Dashboard lives. On the left side, you’ll see a list of identifiers which are all of the apps that you have flipped the
On switch in Xcode for iCloud. Find the app that you created and click on it.
Next, we will set up some things that will help you retrieve data. To retrieve the data you save to iCloud, you need to either
fetch the data. To make doing either of those possible we have to set up some things in the
Schema section of the dashboard. Now just click
New Type then just type whatever type of “thing” you want to save.
This part was kind of hard for me to understand at first. The way I began to think of it was as a kind of category of what your app will be. I don’t think that was the best way to explain it, so here is an example: Say you’re making a note-taking app, a good name for this custom type is
“Note”. Or if you are making a scorekeeping app, name it
This will act somewhat as a
“container” for the data you’ll be saving in your app. So going back to the note-taking app example, inside of the custom type
“Note” you’ll be saving a title and content for each note. So titles and contents of every note you’ll save in the app will be saved under the custom type of
After you are done entering in a name, click
Add Field and enter a
“title” without quotes. Make the
Field Type a
Now under the
Custom Field of the title you just created there is an
Edit Indexes button in blue. Click that and it will bring you to a screen that looks like the following:
Add Index at the top of the screen, it will give you a row that has two dropdowns, one for the
Field Name and one for the
Index Type. I prefer to retrieve the records by the latest one that was modified, so I set it like the following:
You want to make sure to have at least the
modifiedAt be QUERYABLE and SEARCHABLE, and at least
recordName be QUERYABLE. Click
Save Changes in the lower left-hand corner and you’ll return to this screen:
Now with all the boring set up out of the way, it’s time to begin the exciting portion of the tutorial!
Here is all the code for
ViewController.swift. This is a lot longer than any of my other tutorials, so instead of going line by line in this whole thing, I’d prefer to go line-by-line and cover each action that will be performed. The first is
updateBtn, and finally
First off, however:
- Line 2.
import CloudKitjust makes it possible to be able to do all the things we need to with CloudKit
- Line 8.
let privateDatabase = CKContainer.default().privateCloudDatabaseallows us to shorten our code later in the IBActions. I use a private database instead of public or shared because for this project we don’t need to be sharing any data with anyone else.
Also please don’t be intimidated by the long code! When it is broken up it is a lot easier to understand and follow, trust me!
Saving a record is really what starts this whole process, without saving a record first, you cant retrieve, update, or delete anything. Here’s the code for
- Line 3. This is setting the variable
titleto the value of
textFieldin the interface
- Line 5. This is the record of type
“Note”. If you entered a different
Custom Typefrom above, enter that in between the quotes for a string instead of Note.
- Line 7. This is kind of like saving in
UserDefaults, you set a value for a key off of the variable
recordwe created above. In the
iCloud Dashboardwhere we entered
“title”that’s the key for after the
- Line 9. Now all we do is use the
privateDatabasevariable we set in the beginning of
ViewController.swiftand use a
.save method. When it asks what record to save, just use the
recordvariable we created above.
- Line 11–17. This is just error handling at its minimum, if all goes well we should see
And that is it for the saving portion of the tutorial, not too bad right? Next, we will focus on retrieving the records back that we have previously saved.
There are a couple of ways of retrieving records from iCloud. One way is to fetch a record, this only returns one record from the records’ ID you pass to it. The other way is to query all the records. Querying all of the records will retrieve all the records with the sort method you specify.
We are going to query for the records and return them in the order they were modified, which is how we set up the iCloud Dashboard earlier.
- Line 3. This will just tell our query that we would like the records returned to us sorted in some way, we will tell it in which way we want it in a few lines
- Line 5. This is the
querythat will do our retrieving of records, we pass into the
predicatewe set earlier
- Line 6. Here we set how we want the
queryto be sorted, I have entered
modificationDatebecause that’s how we set it up in the iCloud Dashboard
- Line 8. This is us creating an
operation, so when we pass in the
queryvariable, whenever the operation is run, it knows to perform a query
- Line 10–11. This is just clearing the variables, we do this because if we didn’t and we ran a query several times in one app session, then the records would essentially be duplicated in the variables so we just clear them out so we don’t have that problem
- Line 13. This is where we actually get the records from iCloud, it’s important here to just append each record into an array and NOT to update any UI in here
- Line 15–16. Here we are just appending the correct CloudKit types to their respective array variables
- Line 20–29. This is where you’d update the UI, but be sure to do it in a
DispatchQueue.main.asyncthat way you’re not updating UI before the UI is ready to be updated. That part was kind of confusing but just know to update the UI in the
queryCompletionBlockand inside of a
DispatchQueue.main.asyncmethod and you should be OK.
- Line 31. This just adds the operation to the line of things to happen, without this, the query won’t run, so make sure to pass in your
operationvariable to this method.
Retrieving data is probably the hardest thing in CloudKit to wrap your mind around. As with anything in this tutorial, if you don’t understand something, please don’t hesitate to contact me or leave a comment down below.
On to updating records!
As I stated above, we will be using fetch to update records. This is because we can fetch a record given its record ID. Ideally, we would have all of the data displayed in a UITableView, that way we could get the index of the item you wanted to edit and get the record ID element from the
recordIDs variable at that specific index (I’m going to make another tutorial covering that, but we won’t worry about it now).
- Line 3. Here I am hard setting a string that we will update one of our records’
newTitlevariable we set
- Line 5. I am getting a
record IDfrom the array that holds all of them. I am just getting the first one in the array because this is just a demo project, you can customize yours if you want. Also a side note, you have to
save and retrieve your records before calling update, so that there are records that you can actually update
- Line 7. This is where we
fetchthe record we want to update, we pass in the
recordIDof the record we want to update and the method returns a variable for us to be able to edit the
“title” keybut that comes later.
- Line 9. This is just basic error handling, nothing crazy
- Line 11. This is where we set the records’
titlekey to the
newTitlevariable, it is just like when we were initially saving the record
- Line 13–23. This is exactly the same as the
saveBtncode that we wrote earlier, passing in the
recordyou want to save and do some basic error handling…because it is somewhat important.
- Line 29. This is the rest of the error handling from when we were
fetchingthe record to begin with
Updating records can be hard to grasp but if you think of it as two different parts, one that fetches a record by its
recordID and another that is
saving it the same way you did for the
saveBtn, then it should be easier to understand.
Deleting records is just about as easy as saving a record. Let’s take a look:
- Line 3. Just like when updating a variable we need to access a record by its
- Line 5–15. Then after getting a
recordIDfor the record we want to delete, we just…delete it! Call delete on the
privateDatabaseand do some basic error handling…really nothing hard at all!
And that is it for all of the code! It is really not all that bad. Sadly there is still a lot of information to take in with this article.
My opinion would be to take this article a piece at a time. Start with the top and work your way down. Bookmark this and come back to it later. Don’t get intimidated by the amount of information given here.
CloudKit is not something you want to let defeat you mentally, because once you’ve been looking through so many different tutorials, it can get extremely confusing. Hopefully, this one could be the only one you’ll ever need (at least as far as C.R.U.D. goes).
When working with a real app, make sure to do a check every time the app launches to make sure the user of the app is signed into CloudKit. If they’re not, either ask them to sign in or provide a second data persistent layer to make sure none of their data gets lost.
All you have to do now is run the scheme that deploys the app to the iPhone simulator (it may take a few minutes if it’s the first time running the app to the simulator).
Type a message into the text field and click the save button.
- Type a
Save— you should see
Record Savedin the output screen
Retrieveand you should see the
titlesarray output with our one
recordthat we have saved and the
recordIDsarray output with the ID of the one
Updateand it will fetch that
IDwe have for our one record and update it with the new title we have coded into the
Retrieveagain and you should see the new title in the output screen
Deleteand it will access that
IDwe have for our one record and it will delete it
Retrieveagain and you should see two empty brackets in the output screen looking like this: 
I say “that’s it for CloudKit — C.R.U.D” but there is a lot to it.
Using iCloud in your app though will no doubt be really good for user retention and making sure every user can feel as connected as possible using your app. Including CloudKit in your app is definitely worth the time investment if you can make it through all the thick information.
I am continuing on in my quest of attempting to make easy to follow tutorials covering harder topics in the Swift ecosystem.
If anyone at all has any issues with my tutorial or have any questions please don’t hesitate to send me a message on here or leave a reply on this and I will respond as quickly as possible.
Thanks all for reading!
Here’s a link to the GitHub project for this tutorial.