ICloud + Basic Data: First User and User Impression of Data Loss
I have implemented an iPhone app that has about 50k users. Moving from iOS7 to iOS8 many of these users had a terrible feeling when they thought their data was lost.
I implemented the first import behavior I thought was suggested by Apple
1) Users launch the app
2) iCloud automatically starts syncing data previously saved to iCloud
3) At some point, the user receives a notification that the data from iCloud is ready thanks toNSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted
Problem with 3) At some point :
Users who need to sync a large amount of data take minutes to complete sync and in the meantime they feel their data is lost.
I really don't know how to tell my users to wait to sync their data because I don't know when this operation starts .
I am thinking of a possible solution:
During the first launch of the app asking the user if they want to use iCloud. If he wants to use it while creating a database with iCloud options, so I know for sure that syncing starts here (I suppose ...) I'm really not sure how to implement this behavior, since I've always seen the Core Data settings in AppDelegate
, but to achieve this behavior I am assuming that I need to move all CoreData settings in the controller.
What do you think of this decision? how do you work on this problem in your applications?
source to share
Your idea is correct, at least that's what we do. But leave that in appDelegate.
Share with iCloud and non-iCloud when doing "addPersistentStoreWithType". If you do this using iCloud options, it will start directly creating a local store, which is sort of a placeholder (I'm sure you know that, but just to keep my thoughts clear). Once that's done, syncing will start from iCloud. So this is the starting point I figured out what you were looking for.
This process can be viewed through NSPersistentStoreCoordinatorStoresDidChangeNotification notifications and reported to the user triggered by this notification.
If you look at React to iCloud Events in the docs https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/dTP3CHidTP3CHid -SW5 , you will find a detailed desc.
source to share
To summarize, the event description you are describing is part of the transition to accounts process. An account transition occurs when one of the following four events occurs:
- Original import
- ICloud account used changed
- iCloud is disabled.
- your app data is deleted.
During this event, Core Data will publish notifications NSPersistentStoreCoordinatorStoresWillChangeNotification
and NSPersistentStoreCoordinatorStoresDidChangeNotification
to let you know that an account transition is taking place. We need a transition type NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted
.
For your information, I've moved all the Core Data related code to my own manager for simplicity, and used it with the singleton design pattern. When you configure the singleton I file manager for all relevant notifications ( NSPersistentStoreDidImportUbiquitousContentChangesNotification
, NSPersistentStoreCoordinatorStoresWillChangeNotification
, NSPersistentStoreCoordinatorStoresDidChangeNotification
, NSPersistentStoreCoordinatorWillRemoveStoreNotification
). I keep a few details in my settings ( NSUserDefaults
or whatever) like the latest iCloud state (enabled, disabled, unknown), if the initial import was done or not, etc.
As a result, I got an invitation ( UIAlertController
or whatever) to get confirmation if the user wants to use iCloud or not. I have a method displayICloudDialogAndForce:completion:
to do this, and only this if my iCloud status is unknown or I am using the force parameter.
Then, after user input, I call a method setupCoreDataWithICloud:
, a boolean parameter iCloud
based on the user's choice. Then I would set my Core Data stack to cloud or not according to the parameter iCloud
. If I set up using iCloud, I would check my settings against the value of the imported iCloud key (boolean). If the value is NO, then I present a new modal to warn the user about the incoming import, which may take a while.
I have registered my manager for different notifications and on purpose NSPersistentStoreCoordinatorStoresDidChangeNotification
. In my callback, storeDidChange:
I check for the transition type, and if it is NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted
, I change the content of my modal file to show the user that the import was successful and remove it after a few seconds, saving in mine that the initial import was 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...
}
source to share