iCloud in your iOS Apps – Part 1: Setup

In this 5-part series I’ll show you how to use iCloud in your iOS Apps. We’ll discuss the whole picture, starting with how to setup Xcode and your app, including App ID and Provisioning Profiles and I’ll demonstrate how to use all three flavours of iCloud:

  • Key Value Storage
  • Document Storage
  • and iCloud with Core Data

Setup and Prep Work

In this part I’ll explain how to create an App ID, a Developer Provisioning Profile and how to import it into Xcode. We’ll also discuss what else needs to be setup in Xcode to make your app work with iCloud, no matter which flavour you want to use.

Watch the whole series


Watch the full course in one convenient playlist:
Catch this episode on my iOS Dev Diary Podcast:

About Jay Versluis

Jay is a medical miracle known as Super Survivor. He runs two YouTube channels, five websites and several podcast feeds. To see what else he's up to, and to support him on his mission to make the world a better place, check out his Patreon Campaign.

44 thoughts on “iCloud in your iOS Apps – Part 1: Setup

    1. You’re very welcome! I’ve just added the chapter about Document Storage. It was a beefy one and took a bit longer than expected. Now I’ll start recording the chapter about iCloud and Core Data, should be up by tonight. Watch this space 😉

  1. Hello Jay. I purchased the one day pass, so I could look at your core data video. However, it’s not available yet. Can my pass be suspended till it is available?

    1. Hi odelfyette,

      sure thing, I’ve just upgraded your membership so you now have access until next week – the Core Data screencast should be up today or tomorrow.

  2. The 5th part of the series about iCloud and Core Data has just uploaded and is now ready to watch. Thanks for your patience, guys!

  3. Hi Jay, very nice tutorial, very easy to follow. I have set up the codes in my app, every things works fine. However, when it lags a bit before the contents is loaded, but if I get out and get back in the view the contents is there right away. Do you know what might be the cause of that? BTW, I’m not using a NSFetchedResultsController. Thanks.

    1. Thanks gt, nice to hear that! Which iCloud method are you using?

      Sounds like your app is making use of a Table View. Depending on how much data needs to be loaded it can indeed cause a lag on first load. Subsequent loads are faster – I suppose due to caching. What you’re experiencing is more Core Data and Table View related and probably not down to iCloud. To avoid the lag, load your data on app launch, not right before you display it. Alternatively see if you can pre-load on a background thread.

      1. Thanks for getting back to me. I’ve just noticed the contents will show if I just drag the screen a little, but it will take a while if I don’t do anything. I’m using the methods from video #5.

      2. NVM, I found out that I had some methods in the viewWillAppear that’s causing the problem. 🙂

  4. Hi Jay, I would like to add a nice little gif animation while iCloud is syncing. In which of the 3 methods should I do that? Thanks

    1. Since the sync is happening in the background it’s hard to detect. I’d probably start the animation in storesWillChange, and then stop it in storesDidChange. This may be very quick though. I’m not sure if there’s a way to detect when iCloud is downloading data in the background with Core Data.

  5. I am using this, its SO SO SO great – made my life easy. (https://github.com/mluisbrown/iCloudCoreDataStack) but I have an app that already uses core data on the app store and cannot figure out how to add iCloud to an existing app. PS wish i found this intro to iCloud 24 hrs ago, i spent hours trying to figure out what you how in 15 min in that free intro. Great stuff mate

  6. Great tutorials… Regarding the iCloud and Core Data how would you handle if there is a table with Image File names stored externally from SQLite file?

    1. Thanks Podster, glad you like it! I’ve tested this both with internal and external binary data (as declared in the model), and even though the transfer takes a bit longer, Core Data handles this too. Keep an eye though on how much iCloud storage space is used when you save images that way, those log files can grow quite quickly.

  7. Jay, unfortunately for me this is an existing app that is not taking advantage of the Core Data External Binary feature 🙁 I am actually saving the Images in a folder and the Image file name is stored as a Text Field in the Images Table.

    Any ideas on that?

    1. In that case you have to use a combination of Core Data with iCloud for your database, and iCloud Document Storage for the external folder. You can use all three iCloud technologies at the same time.

      1. Will do. One other question 🙂

        I am adding the iCloud to an existing Core Data Universal App (iPhone and iPad) publish in iTunes. What is your suggestion on how to move/migrate the existing Core Data to iCloud?

        I have added the iCloud option in below code but causes a crash (I have existing Core Data).

        NSDictionary *options = @{
        ,NSPersistentStoreUbiquitousContentNameKey:@”Dailybook” // iCloud NEW
        ,NSSQLitePragmasOption:@{@”journal_mode”: @”DELETE”} // v3.8 Restore did not work without this
        //,NSPersistentStoreUbiquitousContentURLKey:@”ChangeLogs” // Optional since iOS7

        Thank you.

          1. 🙂 Got it… Basically at this point in the new iCloud version when the App loads I check for the Database URL name, if it has the new name migration was done. If it is the old name then time to migrate. If you think I should check for already migrated another way please let me know.

            Then the other issue with me will be checking for duplicates since my users could have separate data on the iPhone and iPad.

            Thank you.

          2. Yes that’s one way of doing it, and it’ll work fine. Another approach is to check which version the app is and decide if an upgrade is required or not. Duplicate checking is where the fun begins… Good luck!

  8. HI Jay – Amit here (from the migration question). Another great post. One quick question though; I noticed in the video here for Core Data and iCloud and in the post here : http://pinkstone.co.uk/how-to-use-icloud-with-core-data/ , I’m noticing a small difference. In the video, you simply enabled the iCloud options. In that post, you called a method [self grabCloudPath] which called the method to get the cloud. Is that required?

    I’m building a simple app here which is Core Data with NSFetchedResultsController and because I’ve been struggling with this for some time, I want to make sure to “start” properly with your code and to get this working. Although it’s not difficult to implement that [self grabCloudPath], I wanted to ask if that’s required and a step we should take here.

    The reason I ask specifically is because tutorials I have seen reference:
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *url = [fm URLForUbiquityContainerIdentifier:nil];

    if (url)
    NSLog(@”iCloud is enabled);

    Perhaps this is where I’m going wrong but your guidance would be greatly appreciated.

    Thanks Jay!

    1. That’s just a simple check if iCloud is enabled on the device – there are several ways to do this. I guess in the video I’ve omitted the check in favour of brevity. But yes, for shipping applications it’s good practice to check – either way will work fine. It’s to prevent a non-iCloud enabled device from crashing when you call an iCloud related method.

  9. Hi Jay – without wanting to take too much time from you – I have one final iCloud related question which I can’t seem to get working. I’m so sorry again! I’ve asked a Stack Overflow question (http://stackoverflow.com/questions/24873458/uitableview-in-a-core-data-application-does-not-update-second-devices-main-view) but just not got an answer yet.. its a 4 tabbed tab bar, each with a UITableView which is populated with NSFRC.. but when the iPad connects in as a second device, every tab is populated but the first one (the main view) and that’s where I’ve put the mergeContent code. Interestingly, it ask doesn’t run the storesWillChange and didChange from what I can see!

    Sorry to be asking so many questions – but seriously, you’ve helped me more in one day compared to the last few weeks of troubleshooting!!

    1. Amit! Sure thing, I’ve just read your question on Stack Overflow. This is something that’s more iCloud rather than Tab Bar Controller related. I’ve had the same happen with single view applications (no tab bar involved): according to the log the store is being built from iCloud, you can at that point even test for new objects in Core Data – but the Table View (via Fetched Results Controller) is never updated while the app is live. A restart shows all the content – and it doesn’t make sense.

      I’ve tried everything: rebuild the Core Data Stack, re-fetch all objects, tableView reloadData – nothing.

      Let’s see if we can work this out – it’s been bugging me for months, and my app is suffering from the same issue.

  10. Thanks for the reply Jay and this is indeed a very, very strange one!

    I have been working on it all morning and I haven’t got it working, but it doesn’t make sense to be too far away.

    I have it now so that the iPad (second connected device) doesn’t show up the data, but if I just add an entry to the iPhone (first device), it merges content and synchronises the new and original data across. I don’t need to relaunch the app.

    However, still the data won’t show up originally without that step and I cannot figure out why.

    This post here references a very similar issue (if not exactly the same) http://www.zx81.org.uk/computing/programming/nsfetchedresultscontroller-and-icloud.html and talks about the solution being to refetch fetchedResultsController and reset the cache. I’m not using a cache name and this technique didn’t bring in the data for me.

    My method is: –
    (void)reloadFetchedResults:(NSNotification*)note {
    NSLog(@”Underlying data changed … refreshing!”);
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    [self.fetchedResultsController performFetch:nil];
    [self.timelineTableView reloadData];

    This is being called in the viewDidLoad, and posted in the notification of the App Delegate storesDidChange method.

    According to Apple’s guide https://developer.apple.com/library/prerelease/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/doc/uid/TP40013491-CH3-SW4 , it is important to register for the storesDidChange notification before the addPersistentStore line, and so I’m doing that and it NSLogs out the storesDidChange. But once the container is ready (I’m guessing that means Using Local Storage : 0), then it should post a storesWillChange and storesDidChange, but I’m not getting either posted.

    I can’t imagine we’re too far.. it seems like it’s just a case of making sure the UITableView completely resets the fetchRequest and does it again?

    So close..

      1. Thanks Jay – I’m going to indeed give that a go now. Thanks – I really appreciate your effort with this! The weirdest part is the fact that the storesWillChange and didChange never get called (well DidChange gets called before the addPersistent) and I just cannot understand why it doesn’t get called after the store has been added. So strange!

        1. I’ve just spoken to another iOS Dev Diary member who reminded me: where’s the source code that I’m building in that last video? And right he was (thanks, Eric!) – I’ve just rescued it from a time machine backup. Run that and see if it behaves as expected – I’ll do the same and will add improvements if needed. I’m positive we’ll solve this puzzle together:

          1. Thanks Jay – seriously do appreciate this and I’m looking forward to solving this with you. I’ve just updated the Stack Overflow question to also showcase the persistentStoreCoordinator with the migration code.. and while we could be searching for a needle in a haystack, it could be that I’ve just put the code incorrectly in there which is leading to the lack of notifications after!

          2. Sure thing Amit, this has been bugging me for a while – sometimes the initial import works fine, sometimes it doesn’t. Either way, I think I’ve cracked it: it’s the Fetched Results Controller, that’s playing up!

            Take a look at the 6th video (new as of today) which explains how to fix this. The demo project with this amendment now works reliably across all devices I’ve tested.

            I’ve answered your question in more detail over on Stack Overflow.

  11. That is absolutely brilliant Jay ! (sorry I can’t reply to the previous post for some reason) but it really does make so much sense. I’ve just replied to the SO question that I’m removing the apps, but I think I’m going to try now focusing on putting the notification listeners entirely in the UITableView for the storesDidChange, WillChange and Import and progress from there. It is definitely possible because I can see you’ve done an amazing job to get that working 🙂 Thanks so much for that – I suspect some really bizarre behaviour with why it’s not loading those notifications.. I might try another device to see as well! I’ll report back 🙂

    Thanks again Jay (and for the mention in the video ! 🙂

    1. Unfortunately, I have removed my app from app devices – brought in a new device – removed the iCloud data, restarted my mac and all my iOS devices, but still the storesDidChange and storesWillChange never get run and so the data doesn’t load in to the UITableView. I’m stumped! This is with changing the entire notification listeners to only be in the UITableView, rather than in the App Delegate. Between the using local storage : 1 and 0, I’m expecting the storesWillLoad and storesDidLoad, but both, even though they’re in the viewDidLoad as listeners (implemented in the exact way of the github project), it just refuses to load the NSLogs within those methods.

      Interestingly, in xcode and in the iCloud graphical area, there’s a LOT of entries from previous days, even though I’ve deleted the documents and data from my app on the device settings. I wonder if this has something to do with it. I’ll keep at it – thanks Jay!

      1. Maybe or thread got too long 🙂 Did you try the demo project? Does that behave properly? Works great for me, even between iOS 7 and iOS 8.

        Yes, previous data in iCloud may be a factor. To start with a clean slate you can always head over to Settings – iCloud – (Storage in iOS 8) – Manage Storage, then under Documents and Data select Show All. Find your app and select it (it’s the last part if your Bundle ID), select edit and hit “Delete All”. This will remove all iCloud logs (I’m sure you’ve probably done this several hundred times – just wanted to add it for completion, sometimes it’s the little things we forget).

        1. Thanks Jay 🙂 The sample project works exactly as I would expect – though the first time the app was run on the second device, the storesDid and WillChange didn’t appear in the log, but the data appeared. When I removed the app and tried again, it then worked with the results pulling in and with the storesDidChange.

          One of the differences I can see with my code and yours is :

          (NSManagedObjectContext *)managedObjectContext

          NSManagedObjectContext *context = nil;
          id delegate = [[UIApplication sharedApplication] delegate];
          if ([delegate performSelector:@selector(managedObjectContext)])
          context = [delegate managedObjectContext];
          return context;

          I have this method in my UITableView (the timeline where this is not working) and with a breakpoint set on the NSNotification in viewDidLoad for the storesDidLoad, it went over to that method which went back to the App Delegate.

          There are also a few differences in my App Delegate with :

          (NSURL *)grabCloudPath:(NSString *)filename {

          NSFileManager *fileManager = [NSFileManager defaultManager];
          NSString *teamID = @””;
          NSString *bundleID = [[NSBundle mainBundle]bundleIdentifier];
          NSString *cloudRoot = [NSString stringWithFormat:@”%@.%@”, teamID, bundleID];

          NSURL *cloudRootURL = [fileManager URLForUbiquityContainerIdentifier:cloudRoot];

          NSString *pathToCloudFile = [[cloudRootURL path]stringByAppendingPathComponent:@”Documents”];
          pathToCloudFile = [pathToCloudFile stringByAppendingPathComponent:filename];

          return [NSURL fileURLWithPath:pathToCloudFile];

          Thanks for the heads up on that and absolutely, with each attempt, I’ve removed the app and the iCloud data from settings on the device for my app. So confused 🙂

          I’ll keep trying and I might have to raise an Apple support case for this one (though I sometimes find them less than helpful!!).

  12. I still have some options in the “options” declaration for automatic lightweight migration. What will be the right syntax for adding the NSPersistentStoreUbiquittousContentNameKey??

    Here is my existing options declaration, please add the NSPersistentStoreUbiquittousContentNameKey key to my declaration:

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    1. Hi ronwood27,

      you can add those options at the end of your dictionary. For example, if your current options dictionary looks like this:

      then you can add the NSPersistentStoreUbiquitousContentNameKey like this

      There is an easier way to write this with an NSDictionary literal @ notation, but the above will do the trick.

  13. 🙂 hi Jay, it´s early in the morning now in Germany 01.09 pm. Thank you for the great tutorial.
    The key-value-storage is working fine.
    But I have problems with document-storage 🙁
    I´m using xcode 6.4. My devices: 1 iphone 4 and 1 iPad

    Please look what happened:

    2015-07-20 01:08:43.759 iCloud-Documents[724:60b] *** -[NSFileManager URLForUbiquityContainerIdentifier:]: An error occurred while getting ubiquity container URL: Error Domain=LibrarianErrorDomain Code=11 “The operation couldn’t be completed. (LibrarianErrorDomain error 11 – The requested container identifier is not permitted by the client’s com.apple.developer.ubiquity-container-identifiers entitlement.)” UserInfo=0x147954a0 {NSDescription=The requested container identifier is not permitted by the client’s com.apple.developer.ubiquity-container-identifiers entitlement.}

    May you help me?

    From Iserlohn, Germany

    Olaf Igla

    1. Hi Olaf, glad you’ve enjoyed the video! It’s such a shame that all this worked fine with iOS 7 and Xcode 5, and with iOS 8 Xcode 6 Apple made so many changes that they didn’t tell anyone about – so some of these code samples no longer work.

      In this particular case, my hunch is that the URL for the ubiquity container may be the problem. Try passing nil instead of the values I’ve suggested, that should work if you only have a single container:

      I haven’t had a chance to test this myself (because my health isn’t what it used to be). If this doesn’t work, try stepping through this method with a breakpoint at the beginning, and see which line of code brings up the error.

      PS: I used to live in Germany for many years 😉

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.