Nick Harris

CloudKit + Core Data + NSOperations – Conclusions

with 8 comments

This is post four of four about CloudKit syncing with Core Data. The original post is here. Sample code is here. You’ll need to enable CloudKit and other entitlements in your own environment to get it to work correctly.

Conclusions

The previous posts includes a ton of code. You can see all of it by getting the project from BitBucket. In this post I’ll highlight what I liked and what I didn’t like. I learned a ton while writing it and would again urge you to heed my warning in the first post about it being unpolished and incomplete. 

CloudKit

CloudKit is incredibly powerful. Once I started really diving in I could tell it was thoughtfully created to support almost any type of app someone would want to create. Getting started was relatively easy and the more I learned I think the architectural decisions about how to get the most out of it became easier. Having pre-made NSOperations that handle all of the networking is very nice, even though I found myself subclassing them. Subscriptions are also incredibly powerful for getting any kind of push notifications and background fetching an app might need.

What I don’t like is that it is so generically built – its a strength and a weakness. From my time playing around and researching I didn’t find any real good best practices guidance which made all of the different ways of utilizing it harder to figure out (and I still think I’m wrong with some) as well as possible edge cases I never thought of.

You’re also betting a lot of usability of your app on your users having CloudKit enabled and having enough storage for your app to function appropriately. Using error codes you can build around that and appropriately inform your users of the problem, but they’re more then likely going to blame you instead of Apple. A casual user who paid $10, $20 maybe even $50 for a productivity app but was then prompted to pony up more money to Apple to make it work is a support nightmare.

I also don’t like that its unknown how Apple will handle changes they need to make to keep CloudKit going forward while handling backward compatibility. Its completely reasonable to think that the next version of CloudKit could deprecate all of the NSOperatoins I’m using in favor of new ones that handle problems they may be having server side. It may not be a big deal to refactor, depending how big the changes are, but that’s still a risk that is out of my hands.

The last thing that concerns me is how I would transfer a users private data to another backend system should I ever need to. The device would have to somehow do this at the great expense of the user experience. Imagine running an app for the first time after it updated in the background and it tells you it needs an hour of processing and all of your bandwidth to transfer the data somewhere else. This exact problem came up as my time on Glassboard was ending. The pricing of Azure SQL Server instances was dropping and the code we were using to support Table storage was beginning to show cracks. We didn’t do this but we could have spun up our new SQL instance and a background instance to slowly move our data from Tables to SQL. Our server code could make the process much more seamless to our users then what I would envision with CloudKit.

That being said, for me personally I would prefer a custom backend. I’m probably more biased then most iOS or Mac developers though since I’ve built a few on my own and worked on a handful of others throughout my career. I’ve built them in Java, Node.JS, C# and even straight JavaScript and classic asp pages years ago. I actually miss working on them. Performance tuning a database and server instances is more interesting to me then tweaking auto layout constraints for a day to get an animation to look nice. Not that I don’t love when a app looks sleek when I show it off, but I’d prefer showing off response time improvements more.

For my side project though? I’ll go with CloudKit. I’m building it for myself so I can easily keep up with any changes without worrying about dealing with the support emails.

NSOperation Chaining

I’ve said it before and I’ll say it again. I LOVE NSOperations! Once I found the pattern for passing data I love chaining them even more. CloudKit’s dependencies between zones and records as well as fetching before modifying make NSOperation dependencies close to a no brainer. I also like how I can separate concerns, encapsulate better and have reusable blocks of code I can chain together in many different ways.

It reminds me of one of my last final exams in college where we needed to make a data transformation diagram and detailed writeup showing how we would process a big chuck of data into its many pieces. I wish I could remember what the actual problem we had to solve was but after taking all 2 hours on the final to write it up I promptly empty my brain of it. Someone on twitter mentioned that the approach also resembles monads in functional programming. Just judging from the wikipedia page I’d have to agree but I haven’t explored functional programming very much yet.

Swift

Frankly my love of Swift just keeps growing. The proof of concept uses protocols and enums heavily. I haven’t taken the time to figure out how I would have accomplished the same things in Objective-C but I’m certain I would like my Swift code better. With swift though I learned:

– I love power of Swift Sets. Having intersect and subtract methods is fantastic. 

– Swift higher order functions are also great. I use flatMap a ton in this code. I probably could have used filter and reduce more as well.

– Finding out I could do inline predicates to find the index of an object was a very happy surprise:

// do we have this record locally? We need to know so we can remove it from the changedCloudKitManagedObjects
if let index = changedCloudKitManagedObjects.indexOf( { $0.recordName == deletedServerRecordID.recordName } ) {
    changedCloudKitManagedObjects.removeAtIndex(index)
}

 

– Casting in Swift is powerful in “if let” statements but even better in flatMap. 

– Guard statements continue to be good for me as well though I found I used them much less in this code then my first attempts at Swift.

– I think Swift is much more readable then Objective-C at this point.

– I still hate retain cycles. Seriously. I hate them. Capture lists are nice and all but I hate the fact that I still have to think about memory management.

Series Conclusion

I hope these posts are helpful. Don’t use them as a blueprint for how to use CloudKit but rather a long winded explanation of one persons adventures. Any feedback would be greatly appreciated!

Advertisements

Written by Nick Harris

February 9, 2016 at 6:54 am

Posted in Uncategorized

8 Responses

Subscribe to comments with RSS.

  1. Since you chose to use the private database I was wondering why you didn’t just use CloudKit Core Data that does syncing automatically for you?

    highflyingtv

    March 30, 2016 at 10:10 pm

    • I think because iCloud CoreData is deprecated in iOS10 and there is no alternative from Apple.

      Anonymous

      July 7, 2016 at 12:37 pm

      • Ha good one!

        indiekiduk

        July 7, 2016 at 12:54 pm

  2. Thank you very much for CloudKit + CoreData + NSOperations posts! Found them very helpful!

    Anonymous

    July 30, 2016 at 10:32 pm

  3. Using your method, how do you handle CKAsset ? Every time you want to save the CKRecord into CoreData, the fileURL of the CKAsset is

    Anthony Kersuzan

    September 5, 2016 at 9:56 am

    • the fileURL of the CKAsset is uninitialized

      Anthony Kersuzan

      September 5, 2016 at 9:57 am

    • This code was just a proof of concept. It doesn’t handle CKAsset at all. As I’ve said in previous comments – I would encourage you to find a pattern that works best for your application.

      Nick Harris

      September 5, 2016 at 4:52 pm

  4. I want to sync my apps data with cloudkit but this is horror. It will take me days for my simple app… wtf Apple…?

    Matei Suica

    February 19, 2017 at 5:06 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: