The local account
From the WWDC 2013 207 session about Core Data and iCloud:
You provide us a single store URL inside the application's local sandbox and we then create an opaque container with an entry inside of it for each account on the system, including the local account, which is our term for what happens when there is no iCloud account on the system. This is a special store that's managed by Core Data so that you don't have to do anything special because your user doesn't have an iCloud account.
In iOS 7/OS X 10.9, Core Data with iCloud will automatically use a local account for situations in which iCloud is off. Unlike the fallback store (used when iCloud is on but unreachable), the local account will be wholly replaced by an iCloud account when the service is on, without any merging. The data in the local account is only accesible if iCloud is off. This happens when:
- There is no iCloud account.
- There is an iCloud account, but "Documents & Data" has been disabled.
- There is an iCloud account, but the app has been disabled in "Documents & Data".
The above is what I understand from experimentation. Please correct me if I'm wrong.
When data disappears
Used as is, the local account user experience is awful. If you add data to an app with iCloud off and then turn it on, the data will "disappear" and you might think that it has been deleted. If you add data to an app with iCloud on, and then turn it off, the data will also "disappear".
I have seen examples that try to work around this by adding (more) iCloud settings to the app and managing their own "local" store (not the one provided by iCloud). This reeks of duplicating work to me.
Leveraging the local account for data migration
How about this approach?
- Always use Core Data and iCloud, no matter if iCloud is on or off.
- When iCloud goes from off to on, ask users if they want to merge the local account with the iCloud account. If yes, merge, remove duplicates prioritizing local and empty the local account.
- When iCloud goes from on to off, ask users if they want to merge the iCloud store with the local account. If yes, merge and remove duplicates prioritizing iCloud.
This is similar to what Reminders does. However, Reminders asks the user about data migration directly from iCloud settings, which is something that us developers can't do.
Questions
1) Does this approach have any drawbacks or border cases that might not be obvious at first glance? Maybe we're not meant to use the iCloud-generated local account like this.
2) Are NSPersistentStoreCoordinatorStoresWillChangeNotification
and NSPersistentStoreCoordinatorStoresDidChangeNotification
sufficient to detect all the possible on to off and off to on iCloud transitions?
3) Would you do the user prompt and merging between NSPersistentStoreCoordinatorStoresWillChangeNotification
and NSPersistentStoreCoordinatorStoresDidChangeNotification
, or gather all the information in those and wait until the store is changed? I ask because these notifications appear to be sent in background, and blocking them to perform a potentially long operation might not be what Core Data expects.
NSUbiquityIdentityDidChangeNotification
, however you can rely on getting this notification if your app is not running. NSPersistentStoreCoordinator notifications are not related only to iCloud transitions. For a more detailed explanation see the link in my answer below. There is a pretty detailed explanation on the UIManagedDocument & iCloud Integration page here ossh.com.au/design-and-technology/software-development/… – Gillenwater