I have written an app with Swift 2 using Core Data for persistence. I am thinking about adding a feature to also persist in the cloud. I have read tutorials on Realm and CloudKit, but haven't seen great examples on using them on top of (or along with) Core Data.
I want to:
Can I keep all my Core Data logic and simply add some server calls during CRUD operations using CloudKit (or some other framework)? For example, I use NSFetchedResultsController
for several of my tables, does it make sense to continue to use it while using CloudKit?
CloudKit
and CoreData
do not automatically work together seamlessly, so you will need to write that logic yourself.
There are different types of iCloud storage options, one or two of which do seamlessly integrate with CoreData
, but CloudKit
is not one of them, and CloudKit
is what you will need to use if you have aspirations of enabling your users to share data with others.
AKA: You will need to do the heavy lifting yourself, but if you use good design practices you can do the work once without having to rewrite much of your existing code.
So, here's something similar to what I did in one of my projects that used both frameworks:
Create Core Data object model and NSManagedObject
subclasses like you almost certainly already have.
Turn on CloudKit in Xcode project capabilities and log in to CloudKit Dashboard
Use CloudKit Dashboard to design your record model modeled after your Core Data entity model
(Back in Xcode) Create methods somewhere (most conveniently as extensions to your NSManagedObject
subclasses) that know how to create the given Core Data object from a CKRecord
, and to create a CKRecord
from a Core Data object.
Create one or more Swift classes dedicated to dealing with your CloudKit records and synching them with Core Data. This class(es) would be responsible for performing all CloudKit operations at a high level, including fetching, adding, deleting, modifying, etc. You can design this public API however you want (it should be customized to your needs), but this class would most likely use the methods you created in the previous step to convert to and from Core Data types.
With this approach, your CloudKit specializing class (we'll call it CloudBrain
) does all of the heavy lifting, and if you want you can make it do it all behind the scenes. For example, you could define another class, SyncBrain
, that would automatically listen for changes in the Core Data managed object context, and call corresponding methods on CloudBrain
to ensure all changes are being kept in sync with iCloud. It would also need to do the reverse, listening for changes in iCloud and applying them to Core Data. This will of course require fetching changes initially from CloudBrain
and you'll also want to look into CKSubscription
for real-time updates.
The beauty of this approach is that if you set up all of that correctly, you can keep all of your other code the same, because every time your other classes interact with Core Data, SyncBrain
automatically ensures that all changes in Core Data are reflected in iCloud and vice versa.
As for sharing with other users, this feature is new in iOS 10 and it does not appear as though Apple has yet updated the CloudKit Quick Start. You should therefore watch What's New with CloudKit from WWDC this year.
Important Note: When designing your record model in CloudKit Dashboard, be sure to follow the iCloud Design Guide and not have parent record types with fields holding arrays of a child record type. This is not great performance. Instead, define the child record type to have a single CKReference
field that points to its parent. That way if you need the children for a parent, you can just create a query that requests all objects with their parent set to the parent you want (as opposed to having to wait for all of the children to download when all you wanted was the parent).
Here are some WWDC sessions. Older sessions still contain very useful information but some of it is out of date.
In Xcode 11, you can now mirror Core Data to the cloud. It seems really easy to do as well. You just need to use NSPersistentCloudKitContainer
instead of NSPersistentContainer
. Your data will sync with CloudKit automatically.
See the documentation for more information.
PS. As of writing this, this is in beta.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With