Sample Library Style Core Data Apps with iCloud Integration

WARNING: Apple have deprecated the CoreData iCloud API’s so it is probably best to avoid using them.

CoreDataLibraryAppsiPadCoreDataLibraryAppsiPhone

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)

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:

  1. Create a new App ID by registering on Apple’s Developer Site, select Data Protection and iCloud App Services.
  2. 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)
  3. Download and install the provisioning profile
  4. 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.
  5. Compile and run !
  6. Please let me know if there are other tweaks required to get up and running.

47 thoughts on “Sample Library Style Core Data Apps with iCloud Integration

  1. 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!!!!!!!!!!

  2. 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.

  3. 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.

      • 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.

      • 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.

  4. 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

  5. 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

      • 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?

  6. 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.

  7. Pingback: Migrating existing Core Data to iCloud | lonte facebook

  8. 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

  9. “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.

  10. 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.

  11. 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 😉

  12. 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.

      • 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.

  13. 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.

Leave a reply to Richard Cancel reply