WARNING: Apple have deprecated the CoreData iCloud API’s so it is probably best to avoid using them.
iOS8/OSX10.10 and iOS9/10.11 Swift2 versions can be found here
The beginnings of a Swift 2 version of the sample apps can be found here
Feel free to send donations via PayPal to duncan.groenewald@ossh.com.au.
Features include:
- iOS and OSX Sample Apps with iCloud Integration
- Use of Local or iCloud Core Data store
- Includes a Settings Bundle (note that this creates a settings page in the Settings App) that includes:
- Use iCloud preference setting (ON or OFF)
- Make Backup preference setting (ON or OFF)
- Display application Version and Build Number
- Prompts the user about storage options when the Use iCloud preference is changed to ON
- Migrates Core Data store to and from iCloud depending on the users preference setting and response to prompts
- Detects deletion of iCloud store from another device and cleans up by creating a new empty iCloud store
- Checks for existing iCloud files when migrating local store to iCloud and prompts user whether to merge or discard data in local store if an iCloud file exists
- Makes a Backup of the Core Data store if Make Backup preference is set to ON. Backup file name is persistentStore_Backup_yyyy_MM_dd_HH_mm_ss. To use it:
- set Backup preference ON and next time the app is activated it will make a backup of the current Core Data store and reset the preference to OFF
- file can be copied to PC or Mac from iTunes
- to restore simply set app to use Local files (Use iCloud preference OFF) and replace the persistentStore file with the required backup file (note the file must be called persistentStore).
- Editing record and save/cancel edits in detailed view
- Asynchronous opening of Core Data store to ensure long migrations don’t block the main thread and cause App to be terminated
- Loading of data on background thread with Pull to Refresh in main UITableView to start another background thread (you can start multiple background threads running simultaneously, take care!)
- Display related objects in detailView using UITableView, fetchedResultsController and predicate to filter selection
- Load Seed Data if a no store exists already, checks if iCloud file has been created by another device
- iCloud Upload/Download Status indicator, network activity indicator turns on when Core Data transaction logs need to be synced, are busy syncing, being imported or when background tasks are running
- Sidebar style UI with multiple master and detail views for both iOS and OS X apps
- Backup File Manager which allows you to make backups, copy backup files to and from iCloud, send and receive backup files via email and restore from a backup file(video demo here)
- Core Data Model Upgrades are handled by checking if an upgrade is required and then first migrating iCloud stores to local before performing the lightweight migration (not implemented in iOS version yet).
More detailed explanations for certain aspects of the design can be found here.
Download XCode Projects (latest versions at the end of the list)
- CoreDataLibraryAppv1
- CoreDataLibraryAppv2
- includes checks for existing iCloud files when enabling iCloud and prompts User for merging or discarding local data
- CoreDataLibraryAppv2_1
- includes a Backup option with iTunes file sharing and handling of deletion of iCloud store from another device.
- CoreDataLibraryAppv3
- includes ability to edit record in details view and save/cancel edits
- CoreDataLibraryAppv4
- includes asynchronous opening of the Core Data store to ensure that long migrations don’t cause app main thread to block
- CoreDataLibraryAppv4_1
- added code to prevent user selecting a row while Core Data stack is being set up, added launch screen to simulate long job during didFinishLaunching method.
- CoreDataLibraryAppv4_2
- includes method to launch background thread for loading data, includes a setting to enable this and Pull to Refresh to start a new background thread.
- CoreDataLibraryAppv4_3
- includes display of related objects in detailView
- CoreDataLibraryAppv4_4 and CoreDataLibraryAppOSXv1
- some tweaks and a OS X version
- CoreDataLibraryAppv4_5 and CoreDataLibraryAppOSXv1_1
- updated OS X version to share/remove store from iCloud
- CoreDataLibraryAppv4_6 and CoreDataLibraryAppOSXv1_2
- more tweaks and background threads for loading/deleting data
- CoreDataLibraryAppOSXv1_3
- added another table to show All People (deleting an employee does not delete the person, delete person deletes employee)
- CoreDataLibraryAppv4_7 and CoreDataLibraryAppOSXv1_4
- added loading of seed data if new file is being created, added checks in OS X app when migrating files to prompt user if file exists at target location
- CoreDataLibraryAppv4_8
- added network indicator to indicate when transaction log files need to be or are busy syncing or when busy importing transaction logs or when running background tasks
- CoreDataLibraryAppOSXv1_5 and CoreDataLibraryAppv4_10
- implemented additional startup checks to avoid duplicate data and added image attribute on people to illustrate image conversion(png) between OSX and iOS
- CoreDataLibraryAppv4_11and CoreDataLibraryAppOSXv1_6
- updated UI to use Sidebar Menu style (early work, so detail view not linked correctly in the iOS version)
- CoreDataLibraryAppv4_12
- Updates to correctly handle multiple detail views
- CoreDataLibraryAppv4_14
- Added Backup File Manager
- CoreDataLibraryAppv4_15
- Added send/received backups via email and restore from selected backup file(long press for the popup menu).
- CoreDataLibraryAppv4_17 and CoreDataLibraryAppOSXv1_7
- Warning: Core Data model has changed so delete any existing stores.
- Updated Core Data model to include timestamps. Added base class for NSManagedObject subclasses to handle timestamp updates.
- Updated Backup File Manager to show download status of files.
- CoreDataLibraryAppOSXv1_8
- added backup menu option
- CoreDataLibraryAppv4_18
- updates to OSCDStackManager to ensure managedObjectContext is called from main thread in storesDidChange notification
- CoreDataLibraryAppOSXv1_9 and CoreDataLibraryAppv4_20
- addresses upgrade issues with iCloud stores by checking iCloud store file to see if an upgrade is required and if so migrates it to a local store, removes the iCloud store and then performs the upgrade on the local store and migrates the upgraded store back to iCloud.
- CoreDataLibraryAppv4_21 and CoreDataLibraryAppOSXv1_11
- moved receiving metadata query results onto background thread to avoid blocking in main (UI) thread (iOS)
- added UpgradeViews to display upgrade steps
- and I think that’s pretty much all the basic plumbing done – now to clean-up and make it production quality.
- CoreDataLibraryAppv4_22 and CoreDataLibraryAppOSXv1_12
- add app icons and fixes for iCloud store file detection when backups are stored in iCloud
- CoreDataLibraryAppv4_23
- fixed bug with getting a new filename when copying duplicate backup file to or from iCloud
- CoreDataLibraryAppOSXv1_14
- Added a backup file manager
- CoreDataLibraryAppv4_26
- Minor tweaks for iOS8 (beta) not tested with OSX app yet.
- Note that iOS7 apps will not be able to see any files that have been migrated to iCloud Drive by iOS8 devices
- CoreDataLibraryAppOSXv1_15
- Minor tweaks for OSX10.10(beta).
- Note that OSX10.9 apps will not be able to see any files that have been migrated to iCloud Drive by iOS8 devices.
- CoreDataLibraryAppOSXv1_16
- Updated to show apps container in iCloud Drive, note that only backup files will be visible but they can be copied to and from this location
- CoreDataLibraryAppv4_27
- Updated to show apps container in iCloud Drive, note that only backup files will be visible but they can be copied to and from this location
Demonstration of UI blocking and asynchronous initialisation of Core Data stack
This App is based on the standard XCode 5.1 beta 3 template App. Note that the following are some of the major changes from the standard XCode template:
- Moved all the Core Data Stack creation code to OSCDStackManager
- Modified the AppDelegate to call OSCDStackManager at the appropriate times
- Add a Settings Bundle with Use iCloud and Make Backup preference and display of App version and build numbers
- Modified the MasterViewController to handle Core Data store changes and UI updates from Core Data imports
- Modified the MasterViewController to append “(c)” when a new record is created in a iCloud enabled store.
Future plans for this sample include:
Check for existing iCloud files and prompt user whether to discard local data or merge local data with existing iCloud store(done see V2)Notify user when iCloud store has been deleted (two devices and one removes the store from iCloud most likely because the user chose to stop using iCloud) and prompt to keep a local copy and turn off iCloud(done see V2)Allow user to make and restore backups(done see V2.1)- Provide options to keep iCloud store when deletion is detected from another device
Add code to handle record updates from detailViewController(done see V3)Add main screen activityIndicators to show when things are still busy loading(done see V4)Add video showing App UI and local and iCloud containers(done)Add Sidebar style main UITableView with some sections populated from Core Data store.- Implement robust lightweight migration workflow
Build Steps:
- Create a new App ID by registering on Apple’s Developer Site, select Data Protection and iCloud App Services.
- Create an iOS development provisioning profile selecting the newly created App ID, the developer IDs and the devices to test on (not required for simulator)
- Download and install the provisioning profile
- Unzip the sample app and open it in XCode (note that XCode 5.1 beta3 was used to create it but XCode 5 should work). Set the container ID and bundle name as appropriate for your company and team IDs.
- Compile and run !
- Please let me know if there are other tweaks required to get up and running.
Thank you very much for this sample project. I have been looking for something to help me integrate iCloud with my app. I have the following requirements and am not sure which project I should look at.
1) I need to migrate an existing core data app to iCloud if the user elects to use iCloud.
2) I need to be able to manage updates that come in from the other device (if installed on more than on) – only iOS support.
One other question – if I have two devices that are disconnected and users enters into both devices is there a way to know which record was most recent? I ask because I will need to dedupe the records when this happens and only allow the most current record to win – i.e. I have a planning type app where only a single record can exist for a date, so if I add one on both devices, I want to ensure only the most current remains and I don’t end up with two of the same.
Thanks!!!!!!!!!!
The latest version of the project has more features implemented in it (its a work in progress), so you would probably go with the latest version, but having said that you will need to do your own testing etc. to confirm it works the way you need it to work. The code is provided as sample code only and needs extensive testing before it should be used in production.
With regard to de-duplicating records – you would need to implement your own methods for determining the latest version of a record. Adding a timestamp attribute would be a good way to start.
Personally I would tell the user they should NOT enter data into two separate devices while they are disconnected because of the issues with duplicates or orphans which would be difficult if not impossible to fix automatically.
Thanks!
I’ll look at version 4 above.
My current model doesn’t have a time stamp and I’m reluctant to add one. I was hoping that core data and iCloud had a way to manage that. But if not I guess I’ll need to know which is most recent.
Thanks for the response.
Hey, so basically i can move just a persistent store (not a managed document to icloud), then on another device create a managed document, delete it’s persistent store and migrate the store to that document from icloud?
Yes, that’s effectively what my code is doing. UIManagedDocument provides a neat ‘package’ for the Core Data files, and basic setup for the Core Data stack but not much else.
i was trying to do that, but every time result is unexpected. sometimes i end up with duplicate data, sometimes with no data at all.
What am i doing wrong?
Would you kindly help me out? Please. This is my code:
http://tinypic.com/r/w9bh1e/8
http://tinypic.com/r/2ep11s9/8
what i am trying to achieve is, when user presses export data – persistent store uploads into cloud, when imports, it pulls cloud persistent store to the document. Im using same document.
its been more than a month im trying to understand that :[
to make in clear, when i export from local to cloud, i need so local data is not deleter, but copied to icloud, when importing i need it to be fully deleted and imported from cloud.
Igor – I am not clear on what you are using iCloud for. iCloud is not intended for backups, it is for synchronisation of documents across devices. Anything that gets put in the iCloud container gets synchronised across all devices running the same app. You can’t actually put a file in iCloud (like you can with DropBox). You can only put a file in the local iCloud container from where it will be synchronised with iCloud and other devices (you can’t control this because its done automatically by the operating system). If you just want to make a copy of the local store just copy the entire store file to the iCloud container, and then if you want to restore just copy it back from the same iCloud container.
The usual iCloud/Core Data integration allows the Core Data store to synchronise at a transaction level using transaction logs. The use case you describe seems to be something quite different and not something I am likely to use.
“If you just want to make a copy of the local store just copy the entire store file to the iCloud container, and then if you want to restore just copy it back from the same iCloud container.”
I need exactly that. But i cant achieve that. I want users who were using my app, and then ran it on another device could export data from previous device.
Just use NSFileManager to copy the file, no need to use Core Data transaction replication. I’ll send you an email.
dagroenewald, can’t thank you enough for this amazing tutorial! It’s a lifesaver… but I need exactly what Igor is talking about. Can you please post it here or drop me an email? I would be really grateful! Thanks a million!
I posted some tested code on SO here http://stackoverflow.com/questions/21653136/uimanageddocuments-persistentstore-icloud-backup/21657618#21657618
For some reason I’m getting the “Use of undeclared identifier NSPersistentStoreCoordinatorStoresWillChangeNotification” error. I’m not sure how I should fix this? It’s just in the OSCDStackManager.m
Is this using the unmodified sample application project or are you trying to use OSCDStackManager in another project ?
I had this problem too – it wasn’t recognizing the Core Data methods. Add #import to your .m file and it should clear it up.
Gah – It deleted the code snippet after #import. Add the core data framework.
Add #import to your .m file.
import core data “”
Thank you very much for this sample. What about this small issue?
– (void)performApplicationWillEnterForegroundCheck
{
FLOG(@”applicationWillEnterForegroundCheck called”);
if (_useICloudStorage == -1) {
FLOG(@”_useICloudStorage is %@”, (_useICloudStorage ? @”YES” : @”NO”));
}else {
FLOG(@” _useICloudStorage is NIL! XXXXXXXX”);
}
if (_isOpening) {
FLOG(@” store is busy opening!”);
return;
}
Comparison of constant -1 with expression of type ‘BOOL’ (aka ‘bool’) is always false
Yes, thanks – is that still around in the latest versions? I did fix that.
Dear dagroemewald,
When testing application on the device, I found the following issue:
1. When launch app first time and choose only local store…
2. After go to the app settings and set “use icloud” …
3. When launch again application freezes.
You need rebuild on XCode to solved this issue. How to fix that problem?
Excellent! Excellent! Excellent!
Thank you very much.
Hi,
Your sample app works great! But I figured out it has a smilar problem i ran into with my app development.
I’m trying to sync core data between OSX and iOS but somehow they’re not using the same container. I tried your apps and they have the same problem(even using the same ubiquity container).
Is this something you cannot solve in production or do you have solution to force osx and iOS to use the same database.
See this stackoverflow thread:
http://stackoverflow.com/questions/22668172/icloud-coredata-use-same-ubiquity-container-between-osx-and-ios
Best regards,
Arno
The apps work fine for me and synchronise between iOS and OSX – take a look at the iOS OSX integration video to see it working. If they are not using the same ubiquity container then thats because you have set them up to use different containers. They must use the same container ID and the same NSPersistentStoreUbiquityNameKey.
Pingback: Migrating existing Core Data to iCloud | lonte facebook
The iOS app (v4_23 — the latest, I believe) crashes when run on the simulator (iPhone) and one attempts to view the details for a person. Seems there are several outlets set in the storyboard that are not still connected into the code. Any idea how that got broken?
I don’t think I ever connected all the UI fields in the iPhone version of the storyboard. I think the iPad version should work. Apologies, this is intended to illustrate how Core Data/iCloud integration can be achieved, it’s not a fully functional App, so completing all the wiring is left as an exercise for the reader.
Regards
Duncan
“If you just want to make a copy of the local store just copy the entire store file to the iCloud container, and then if you want to restore just copy it back from the same iCloud container.”
I need exactly that. But i cant achieve that. I want users who were using my app, and then ran it on another device could export data from previous device.
You should find the code to copy the store file to and from iCloud in the sample apps.
Your implementation of the getter of the ‘persistentStoreCoordinator’ property will return nil. The creation block of the PSC below will never be reached.
Your implementation of ‘doesICloudFileExist’ will always return YES at the end, why is this?
Umm, not sure, it’s been a while. Possible because I knocked it together in a couple of weeks and there were always a few loose ends. Have just started a Swift rewrite for new iOS 8 apps so will post a Swift CDStackManager/sample sometime.
Hello, such great stuff I’m trying to incorporate it into my app I’m attempting to develop. I have a split view controller that loads your backuptableviewcontroller and creates or restores backups. COOL! but the masterviewcontroller’s fetchedResultsController doesn’t see the new persistentStore after a backup. Creating a new entity caused a crash “Illegal attempt to establish a relationship ‘owner’ between objects in different contexts…”
Outside of your OSCDStackManager I’m getting the context with
context = [[OSCDStackManager sharedManager] managedObjectContext];
is there a way to get the current, after a backup has been restored, context for my other viewControllers?
I’m catching the OSDataUpdatedNotification and OSStoreChangeNotification notifications and trying to re-read the context then too. And in the ViewWillAppear functions.
Weekend code warrior floundering 😉
ps. The restore backup works, I just have to restart the App to see it
Solved it. I knew the problem was in my code! I needed to delete the fetchedresultscontroller cache and nil it out. then table reloads the current data.
Good job, no need for any help then 🙂
Hi Duncan… what is the license for this code?
Free to use, hope it helps. Be aware there are a few scenarios not catered for so make sure you test it well.
Hi Duncan,
Happy to of found your site 🙂
In the iCloud Design Guide it mentions the following:
“When users launch your iCloud-enabled app for the first time, invite them to use iCloud. The choice should be all-or-none”
My application (built using iOS8 and Swift) is currently doing this but I would prefer to have an iCloud On/Off switch in the Settings bundle and depending on the situation migrate the Core Data store to and from the Local and iCloud locations.
I doubt the user will do this often but should they decide then their data will still be present on the device. Rather than an all-or-none where the storage would appear empty should they turn On/Off.
Please, don’t think I am rushing you, but may I enquire about the progress of this?:
“[FYI: iOS8/OSX10.10 Swift version in the works, hopefully in the next month or so]”.
I’m really hoping it can help point me in the right direction. Am I right in thinking that I need to implement the following:
– check if iCloud is available
– if available then invite user to use iCloud storage
– either use Local or iCloud storage (save preference)
– register for notifications should iCloud toggle change in settings
– implement mirgration of Local to iCloud or iCloud to Local
– delete storage not used
I’d welcome any pointers on this process. I’m mostly stuck with how to do the migration and clean up.
Thank you in advance.
You have the gist of it correct, unfortunately there are quite a few more scenarios you have to cater for. I might try writing a comprehensive post to explain them, if they are not already explained in one of them.
With regard to the Swift rewrite – its probably 75% of the way, new shell app is done and most functions for the CoreDataStackManager have been migrated. I had forgotten how many functions there are! Swift, in some ways, adds more code than it takes away. Simpler more consistent programming syntax though.
Hi,
Very keen to hear how you’re coming along with the Swift rewrite.
Have there been any hurdles?
Thank you in advance.
Not so far, just a rather tedious and repetitive effort. Forgotten how much code there is ! Swift handling of null values means quite a lot more lines of code but probably results in much more robust code. Have not had much time to see what the philosophy behind it is. Been on hold for the past 3 weeks, just been going live with a bunch of self-service Health Stations for SISUWellness.
Check this link for my attempt to explain the scenarios you need to deal with in your app.
Thank you very much for the quick but detailed reply.
The scenarios you list make sense in the way they flow, and yes, there are a lot more than expected. 🙂
I now just need to do more research on how to implement them.
Looking forward to your Swift Rewrite. It will be good to compare and see where I inevitably will go wrong.
Hi Duncan,
Great to have found your site 🙂
I’m currently developing an app (iOS8 / Swift) with iCloud integration.
The iCloud Design Guide states the following, which is how my application is currently working:
“When users launch your iCloud-enabled app for the first time, invite them to use iCloud. The choice should be all-or-none.”
However I would actually like to give the user the ability to toggle iCloud On/Off in the Settings screen. Users wouldn’t do this often but should they decide then the Core Data would still be present and not blank when switching stores.
Am I correct in thinking that I need to implement the following?
– see if iCloud is available
– if available ask if user wants to use iCloud
– create Core Data based on their decision (save location)
– register for changes to the iCloud toggle
– on change migrate data to Local or iCloud
– remove unused store
I’m just really struggling with how to implement the migration and clean up.
Please don’t see this as rushing you but could I please enquire on the progress of this?
“[FYI: iOS8/OSX10.10 Swift version in the works, hopefully in the next month or so]”
Thank you in advance.
I don’t register for changes in the iCloud account but check this when the app is brought to the foreground. Given the user could not change those settings without switching the app to the background this also allows me to check whether the user might have changed the apps iCloud preference (using the apps Settings bundle).
The Swift CoreDataStackManager code is on the site, look for the migrate methods.