Blog

close
April 9, 2020

CloudKit Impressions from a NetNewsWire Developer

I just got done implementing iCloud support in NetNewsWire. We are still doing preliminary testing on it and aren’t ready for public testing. I don’t know which release it will be in unfortunately. That depends on how initial testing does and then public testing.

I thought I’d write up some my initial impressions of CloudKit. This isn’t a tutorial although you might find some of the information useful if you are looking to develop with CloudKit.

Education Process

The process for learning any major technology from Apple seems to be about the same and I found CloudKit no different. I read a couple blog posts on CloudKit when I got started. Then I watched some old WWDC videos on it. Then I searched Github for open source projects using it and read their code. Then I implemented it while relying on the API docs.

I found reading the code from an actual project to be most helpful. A blog post and couple WWDC videos only get you to the point that you are dangerous to yourself and others. CloudKit has some advanced error handling that needs to be implemented to work at all. It is hard to pick that up from only a few sources.

Implementing basic sync

The hardest part about implementing the basic syncing process was leaving my relational database design knowledge behind. A CloudKit record is not a table, even if superficially they look the same.

This becomes very obvious when you look at how you can get only the items that have changed in a database since the last time you checked. CloudKit has a feature that will return you only the changes to records that have been made which saves greatly on processing. You don’t necessarily get those changes in an order that you can rely upon, so managing complex relationships between records isn’t recommended by me. I ended up doing a couple things that went against all my training to get it to perform well.

Once you figure out how to model your CloudKit data and understand the API’s, things fall together fairly quickly. We have other RESTful services that do syncing in NetNewsWire, and CloudKit is the most simple implementation we have.

One area that CloudKit outshines our RESTful service implementations is that it gets notifications when the data changes. This keeps our data more up to date. In the RESTful services, we sync which feeds you are subscribed to every so often via polling. This happens at shortest around every 15 minutes. Realtime updates to your subscription information isn’t necessary, but it is fun to add a feed on your phone and watch it appear in realtime on the desktop.

Advanced syncing failure

One thing I wanted to do was provide a centralized repository that knew which feeds had been updated and when. I planned to have a system that would use the various NetNewsWire clients to update this data and notify the clients. My theory was that checking one site for updated feeds would be faster than testing all the sites to see if their feeds had updated.

I ended up giving up on this task. I think it would have been possible to implement in CloudKit, but would not have been faster than checking all the sites for their feed updates. You see, we can send out hundreds of requests to see if a feed has been updated all at the same time. Typically they return back a 304 status code that says the weren’t updated and they don’t return any data at all. This is very fast and all the site checks happen at the same time. This is how the “On My Device” account works and it is very fast.

The reason I couldn’t get CloudKit to work faster than checking all the sites individually comes down to one thing. There is no such thing as a “JOIN” between CloudKit records. If I could have connected data from more than one record per query I could have done some data driven logic.

What I wanted to do was have one record type that contained information about all the feeds that NetNewsWire iCloud accounts were subscribed to. This would contain the information about if the feed had been updated. I needed to join this to another record type that had an individuals feeds so that I could restrict the number of feeds that a user was checking for updates.

I could have implemented something that didn’t use the “JOIN” concept, but it would have required lots of CloudKit calls. This required me to pass the data I wanted to JOIN in every call. It would have been unnecessarily complex and not performed better than just checking the site.

Conclusion

I think that CloudKit is amazing for what it is intended to do. That is syncing data between devices. I think it has potential to do more and I’ll be watching to see if Apple extends its capabilities in the future. There may be more yet that we do with CloudKit on NetNewsWIre.