, 25 tweets, 5 min read Read on Twitter
For the past 2+ years I’ve been building my side project using #CloudKit and I’d love to share what I’ve learned.

There isn’t a ton of info out there on it, and I’ve got some tips that I’m not sure I’ll get around to blogging about so I’ll add them here in a thread 👇
First off - subscriptions. There are three main types:
CKDatabaseSubscription
CKRecordZoneSubscription
CKQuerySubscription

Unless you’re *only* using the default zone, you should start with CKDatabaseSubscription.
The reason is it vends custom zone changes and more importantly changes from a shared database. RecordZoneSub can’t do this, neither can a query sub.

If you know you’re for sure not supporting sharing, you can get away with a recordZoneSub *mostly*.
So your flow will be:
Subscribe to database changes from your private *and* shared databases.

Next, get record zone changes from the database subscription and then pass those into a CKFetchRecordZoneChangesOperation.

You’ll see both shared and custom zone record CRUD ops now.
2) CKRecords and your Models.

At first I loosely coupled them but I’d argue to tightly couple them. If you generate a new one on the fly each time its change tag is new too, not what you want.

You need to cache the record along with the model to persist that.
Using dependency injection to just pass a record into a model and set properties accordingly. In getters and setters their record counterparts are edited. Then I just pass those to CloudKit when I need too.
With your models, also go ahead set the parent property of its CKRecord if it’s got a back pointer (think a list item being part of a list).

If you’re using .deleteSelf on an existing one you’ll need to set a new reference as the parent, these CKReferences require .actionNone.
Anyways - this sets you up to already have a sharing hierarchy in place if you want to add CloudKit sharing. Doing this you’ve only got one root record you need to share and you’re all set.
3) Fetches

One thing that might feel weird at first is you get deleted record IDs, and then changed records. So it’s on you to see if you’ve got a “changed” record in your cache or not, i.e. is it new or an edit?

Might not be a big deal for some but it was for me.
This one is important - sort your incoming changes by record type “top down”, that is - apply edits to your parent objects first. This is due to back references, and it’ll help you avoid orphaned objects.

So if you have lists -> list items, deal with lists first then list items.
With CloudKit’s back references, children know about their parents but not vice versa. This isn’t like traditional programming so it’s important to remember. If you’re using a DB, then in my example a list item’s foreign key would be the list’s ID.
Also, on the topic of IDs - you’ll link your models to their CKRecord via a record’s recordID name. This is unique per record and is your consistent ID for data across devices.

Remember, the server is the truth, CloudKit is the glue and your local cache is representing that.
Also with fetches - you need to cache your server change tokens. You need to do this per database *and* per each zone. In my code, each CKDatabase extension tracks:

1) Its database change token
2) A dictionary for each zone change token, i.e. <CKRecordZoneID *, CKChangeToken *>
4) Quality of Service

Are your requests lasting a long time, like SEVEN DAYS? That’s because you didn’t set your operation’s qualityOfService property and CloudKit chose for you....and it chose utility 🙃.

Set this accordingly for each operation.
5) WatchKit

If you’re building a WatchKit app - you can pretty much skip the connectivity framework and just query CloudKit 👌 Their API is strikingly similar across platforms.
6) Saving Data

A lot of sample code, when saving, uses the most relaxed save policy. Is it easiest? Yeah. Is it a good idea? Probably not. Apple made forced locks the default for a reason so I’d opt to use them. I only use .chnagedKeys in one place, and it’s to force edits.
A reason why I think developers do this is at first error handling is intimidating with CloudKit. But really you can think as a lot of them as warnings with helpful info much more than a traditional error.

This ties into saves because...
If you don’t have the most recent record change tag or it’s been modified you’ll get an error. But the error gives you a copy of the client record, the server record and the local record. It’s not too much hassle to reconcile things from there. My app does it silently, no issue.
7) Sharing

I won’t go huge into implementation details but the flow doesn’t really seem to be documented super clearly so I’ll lay it all out here from start to finish. This assumes you’ve got your record hierarchy setup correctly as mentioned before.
- You need to add the cloud kit sharing entry into your .plist.
- Use UICloudSharingController one of two ways. Either you’ve shared already, so fetch the record and pass it with the container to the initializer. Or, you supply a preparation handler to create the share initially.
- Set the cloud sharing delegate so you can know when it was shared, if it failed and if it stopped. You’ll need to handle each of these scenarios.
- Person accepts the share. Handle the delegate method and use the operation on CKContainer to pass the metadata and accept it.
- Now your CKDatabaseSubscription in your shared database fires, you get the new zone recordIDs and pass those to the fetch zone op to get the shared records. For the other person, this is reflected in their private database subscription.
Rememeber shares are just a view into the other person’s private database. As such, any records added go towards their iCloud limit.

Anyways if you’ve got resilient data, diffing and batch updates you’ve now got real-time collaboration which is awesome.
8) Error Handling

I won’t spend a lot of time here. If you’ve watched any of the CloudKit sessions, they all mention how important it is to handle all errors and they’re right. There’s something like 22 to look out for, it’s difficult at first but really it’s not a huge deal.
A bigger deal is if you ignore them. You’ll have a bad time 😬 Some are as simple CloudKit just passing you a double value to try the request again after X amount of seconds.

Anyways, I think that’s about it! Hope it helps a #iosdev out there!
Missing some Tweet in this thread?
You can try to force a refresh.

Like this thread? Get email updates or save it to PDF!

Subscribe to Jordan Morgan
Profile picture

Get real-time email alerts when new unrolls are available from this author!

This content may be removed anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!