This Tutorial shows you SyncKit, a great Solution for syncing your data using CloudKit between devices instead of iCloud Drive with Core Data, because of Core Data stores with ubiquity options have been deprecated. I’m going to create a simple model, where companies have departments and employees are in departments. I’ll import at launch CoreDataDefaults, exactly 5 Companies. After that I’m going to add new departments and employees too. With a Sync button, I will sync these Data with CloudKit.
Because of I import companies at first launch, if the user deletes the app, and later install it again, these will duplicate. Avoid this, I’m going to use QSPrimaryKey identifying objects, so if the Name of the Company already exists, that will be not synced again, that will be not duplicate neither in CloudKit nor local.
First of all you need to create this or a similar CoreData Model. You have to avoid many-to-many relationships, if you want to use CloudKit. For other warnings please check the Readme of SyncKit! For CoreData Tutorials click here!
Create a new Single View project with CoreData. Check AppDelegate.m, it must have Core Data stack.
Create a Podfile with SnycKit. Check this beginner tutorial for Cocoapods.
For SyncKit use in the Podfile what you find for version in the Readme on Git, or if you want to use QSPrimaryKey as an ObjectIdentifier to avoid duplication in CloudKit, you should update SyncKit pod for 0.3.1 version.
Install pod, and now you can open the workspace and start to work.
Create these attributes, and relationships. Pay attention for the To One and To Many relationships (Department —> Company relationship is To One, but company —> Department is To Many). I am using now Nullify as delete rule. (you can learn more about CoreData basics and Delete Rules here).
Editor —> Create NSManagedObject Subclass…, select the Data Model, select all entities.
In you Companies+CoreDataClass.h add QSPrimaryKey Protocol:
And in Companies+CoreDataClass.m return your primaryKey identifier as a NSString:
I use the name of the company, because they are always unique, so my primaryKey will be the “cName” property.
If you have problems with subclassing your Entities check 8.1 for solution.
We need to check, if this is a first launch, and if yes, we need to save the first 5 companies.
In AppDelegat.h add a FirstLaunched
@property(nonatomic) BOOL FirstLaunched;
In ViewController.m in ViewWillAppear create an NSUserDefault for check the bool value for FirstLaunched, and if it is the first launch, set the bool YES and call a function named importCoreDataDefaults.
In ViewController.h create ManagedObjectContext and ManagedObjectModel, synthesize them in .m file. Import Companies+CoreDataProperties.h in ViewController.m file and create the first 5 company with properties, and save it in CoreData.
Create an Fetch Request Template in DataModel to fetch all company object in ViewDidLoad, so you can see the count of the companies in your Log.
Create the buttons on the Storyboard the buttons and their properties and actions:
Use this Code to create and save new Department and Employe Data if you click the Button. With NLog we can see them in log, so we don’t need to create TableViews and manage rows to check the data. Of course you will do it in your real App :)
..to check the count of Departments/Employees, and after that you can create a new one with attribute, which depends on the count. You can list all objects of the array in log if you want to check not just the count of the objects.
At the Project Target in the Capabilities set iCloud on, and tick CloudKit. Better to use default container, which is the Application Bundle name. CloudKit containers can’t be deleted, so you should sure, that you are using a final bundle name for your App.
In AppDelegate DidFinishLaunchingWithOptions create a UserDefault with “iCloudEnabled” Dictionary. And call a function, which check, whether the user is signed in iCloud.
Implement the iCloud functions after the SaveContext method in AppDelegate.m. The first check, whether the user is signed in iCloud, the second checked, that iCloud is enabled by user on the device.
Now you can implement SyncKit methods as you can read it.
In AppDelegate.h file import & delegate QSCoreDataChangeManager:
@interface AppDelegate : UIResponder <UIApplicationDelegate, QSCoreDataChangeManagerDelegate>
And Create a synchronizer property:
@property (nonatomic, strong) QSCloudKitSynchronizer *synchronizer;
I completed this method with the user iCloud availability control. Here you have to check the container name, which is very important, it must be the same as your CloudKit container, iCloud.com.maybeHereComapnyName.AppName.
And add the sync function, which call the synchronization, and at the end I call the companies fetch request, to check the companies count again. That will be important to check the deduplication after the second installation.
In AppDelegate.m implement:
and changeManager didImportChanges:
Here at did ImportChanges I check the companies count again.
In AppDelegate.h don’t forget the sync function:
After that you can call it from ViewController.m, when the Sync button clicked:
Now everything is ready to test!
Before start the test, open your CloudKit Dashboard (at Project Target —> Capabilities —>iCloud click on the CloudKit Dashboard button. You have to be logged in with your Apple Developer ID.
You will see this dashboard, without any Record Types or Records (just the default Users Record Types).
If you have linker command failed with exit code 1 (use -v to see invocation) error because of symbol duplication in CoreDataClass files. You have to set Manual/None Codegen at the Entitiy instead of Class Definition. And the Global Space to Current Product Module if it's necessary.
After the first launch your log will notice you about the user iCloud account and availability, and about the first import.
If you click the Add Department button, in your log you will see, that you have 0 departments, and after that you saved the first one. Click it again, and you will see, now you have 1 department, and you added one more.
Click on Add Employees, and see the log. Now, if you have Companies, Departments, and Employees too. Click the Sync button. Now you can see the whole Sync process, how many records have been uploaded, downloaded, and how many companies you have.
Relaunch your CloudKit Dashboard, and you will see the Record Types.
You can run it again, and you can add more Departments, Employees, and you can Sync them again.
You will see, that the departmentsArray count is increasing.
You can add again Departments, Employees, and you can Sync them. After your sync, you should see the Companies count stay just 5! (If you don’t use PrimaryKey, it will duplicate to 10).
Stop the App, and Run it Again! Just tap the Sync button, and after the “Add Department” button. Now you will see, that you have 5 departments and you add the 6th. Don’t tap the Sync button again, so in CloudKit stay 5 departments.
You will see 5 departments, and you add the 6th again. Because you deleted the App, your 6th department, what you added before is disappeared, and stayed just those 5, which saved in CloudKit.
You will see in CloudKit Dashboard your Records too, the Companies stayed 5 after new App install with new import. And you can check the Record counts at Departments and Employees too.
Run the App on your second Device(I’m using an old iPad with IOS9 which works great too ). First click Sync button. You will see, the 5 companies, and the whole Sync process.
Tap twice the Add Departments button. Now you have 7 departments, but just 5 synced, so tap Sync button.
After your synchronization, open the App on your first device (Run from Xcode to see log).
Tap first Sync button, and after that Add Department. You had on this device 5 synced and one more department, and now after you synced, you have 7 synced (5 from earlier, and 2 from the other device saved and synced) and 1 more department (not synced), and if you tap the Add Departments button, it shows you all 8 departments, and because of this button add a new one, you will see in log d1 saved, and 1 new insertion.
Download the Xcode template from Github.
The next part of the series: later with further development of SyncKit. Migrations and Sharing.
If you would like to be notified of my new solutions, please subscribe to my Newsletter or my youtube channel and/ or follow me on Facebook or Twitter! Check Footer section for these opportunities!