MatterGoal
MatterGoal

Reputation: 16430

iCloud + Core Data: First import and user's feeling of loss of data

I've implemented an iPhone application that has around 50k users. Switching from iOS7 to iOS8 a lot of these users have experienced a terrible feeling when they thought that they data get lost.

I've implemented the first-import behaviour that I thought was the one suggested by Apple

1) Users launch the App

2) iCloud, automatically, starts synching data previously stored on iCloud

3) At some point user get notified that data from iCloud is ready thanks to NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted

The problem is with 3) At some point:
Users that have to sync a lot of data need minutes to get the synch completed and in the meanwhile they think that their data is lost.

I really don't know how to let my users know that they have to wait to see their data synched, because I don't know when this operation starts.


I'm thinking about a possible solution:

During the first launch of the App, asking to the user if he wants to use iCloud. If he chooses to use it, building the database with iCloud options, so I know exactly that the synch is starting here (I suppose...) I'm really not sure about how to implement this behaviour since I've always seen Core Data settings into the AppDelegate but to achieve this behaviour I suppose I need to move all the CoreData settings in a Controller.

What do you think about this solution? how are you working around this problem in you Apps?

Upvotes: 3

Views: 313

Answers (2)

HiDeoo
HiDeoo

Reputation: 10563

To summarize, the event you're describing is part of the account transitions process. An account transition occurs when one of the following four events is triggered:

  • Initial import
  • the iCloud account used did change
  • iCloud is disabled
  • your application's data is deleted

During this event, Core Data will post the NSPersistentStoreCoordinatorStoresWillChangeNotification and NSPersistentStoreCoordinatorStoresDidChangeNotification notifications to let you know that an account transition is happening. The transition type we're interested in is NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted.

For information, I've moved all Core Data related code to my own Manager for simplicity and use it with a singleton design pattern. While setting up the singleton, I register the Manager for all relevant notifications (NSPersistentStoreDidImportUbiquitousContentChangesNotification, NSPersistentStoreCoordinatorStoresWillChangeNotification, NSPersistentStoreCoordinatorStoresDidChangeNotification, NSPersistentStoreCoordinatorWillRemoveStoreNotification). I store several informations in my settings (NSUserDefaults or anything) like the last iCloud state (enabled, disabled, unknown), if the initial import is done or not, etc.

What I end up doing was having a prompt (UIAlertController or anything) to get a confirmation if the user wants to use iCloud or not. I have a displayICloudDialogAndForce:completion: method to do that and only do that if my iCloud state setting is unknown or I use the force parameter.

Then, after the user input, I call a setupCoreDataWithICloud: method, the iCloud boolean parameter depending on the user choice. I would then setup my Core Data stack, on the cloud or not according to the iCloud parameter. If I'm setting up using iCloud, I would check my settings for the value of an iCloud imported key (boolean). If the value is NO, then I'm presenting a new modal to warn the user about the incoming import that could take some time.

I've registered my manager for different notifications and specially NSPersistentStoreCoordinatorStoresDidChangeNotification. In my storeDidChange: callback, I'm checking the transition type and if it's NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted, I'm changing the content of my modal to show the user that the import was successful and removing it a few seconds later, saving in my settings that the initial import is done.

- (void)storeDidChange:(NSNotification *)notification 
{
    NSPersistentStoreUbiquitousTransitionType transitionType = [notification.userInfo[NSPersistentStoreUbiquitousTransitionTypeKey] integerValue];

    if (transitionType == NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted) {
        [settings setDefaults:@(YES) forKey:kSettingsICloudImportedKey];
        [ICloudModal dismissWithSuccess];

        // ...
    }

    // Do other relevant things...
}

Upvotes: 2

Red
Red

Reputation: 1469

Your idea is right, at least it is that what we do. But leave it in the appDelegate.

Differentiate between with iCloud and without iCloud when doing the "addPersistentStoreWithType". If you do it with iCloud options, it will directly start to build the local store which is a kind of a placeholder ( I'm sure you know that, but just to make my thoughts clear). As soon as this is done, the sync starts from iCloud. So this is the starting point I understood you were looking for.

You can watch that process using the notifications by NSPersistentStoreCoordinatorStoresDidChangeNotification and inform you user accordingly triggered by that notification.

If you look at "Reacting to iCloud Events" in the docs https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/doc/uid/TP40013491-CH3-SW5 there is a detailed desc.

Upvotes: 2

Related Questions