Closed NorbNorb closed 10 years ago
Just configure USM to use the new store and in -ubiquityStoreManager:willLoadStoreIsCloud
check to see if there's an old store. If there is an old store, open it and copy all entities to the new store. That way, by the time USM starts up, your new store will be populated.
To make the process easier, you could use -migrateStore
provided by USM. This will copy all entities from one store to the other. You may need to specify the UbiquityStoreMigrationStrategyManual
strategy and implement -ubiquityStoreManager:manuallyMigrateStore:toStore:
.
/**
* Migrate entities from one store to another.
*
* NOTE: Use this only from the persistence queue (see UbiquityStoreManagerDelegate method documentation).
* You probably want -ubiquityStoreManager:willLoadStoreIsCloud:
*
* @param migrationStoreURL The URL to the store file of the store from which to copy data.
* @param migrationStoreOptions The options to use when opening the migration store. If they include NSReadOnlyPersistentStoreOption and
* the store file is accessible, we'll migrate a copy of the store to allow store model migration if necessary.
* May be nil, in which case we'll determine default options depending on what the migrationStoreURL is.
* @param targetStoreURL The URL to the store file of the store into which the data should be copied.
* @param targetStoreOptions The options to use when opening the target store.
* May be nil, in which case we'll determine default options depending on what the targetStoreURL is.
* @param migrationStrategy The strategy to use for performing the migration.
* May be 0, in which case we'll use USM's default migration strategy.
* @param outError When the migration fails, this will point to an NSError object that describes the failure.
* @param cause When the migration fails, this will point to the cause of the problem which indicates when the failure occurred.
* @param context See the documentation for the cause to determine what the context will be.
*
* @return NO if the migration was unsuccessful for any reason. YES if the target store contains the migration store's entities.
*/
- (BOOL)migrateStore:(NSURL *)migrationStoreURL withOptions:(NSDictionary *)migrationStoreOptions
toStore:(NSURL *)targetStoreURL withOptions:(NSDictionary *)targetStoreOptions
strategy:(UbiquityStoreMigrationStrategy)migrationStrategy
error:(__autoreleasing NSError **)outError cause:(UbiquityStoreErrorCause *)cause context:(__autoreleasing id *)context;
Dear lhunath,
thanks for your answer. However, I think you mean how to do a custom migration. Our app can do this already in the new version. It starts a migration on the local iCloud store. But not all devices will update at the same time. So what to do if one device updates to the newest data model (and migrates) and the others haven't yet?
Don't destroy the old store?
I'm sorry if I have a problem in understanding this, but in my opinion iCloud cannot handle an app using the iCloud store under two different data model versions. It's simply a question of time until the developer has to change the Core Data schema and cannot use lightweight migration.
I was able to migrate the (local or iCloud) store on the device itself, but the zoo of devices using both older and newer model versions AND sharing a single iCloud account didn't work for me. So what's the correct handling if I have to upgrade my data model with respect to not losing data on iCloud?
you can easily put different stores on iCloud, each with different data models. USM by default merges all the data models when it opens the store you tell it to open, but you can specify a custom model if you prefer. Just use a different content name for each store that uses a different data model.
See:
/** Start managing an optionally ubiquitous store coordinator.
* @param contentName The name of the local and cloud stores that this manager will create. If nil, "UbiquityStore" will be used.
* @param model The managed object model the store should use. If nil, all the main bundle's models will be merged.
* @param localStoreURL The location where the non-ubiquitous (local) store should be kept. If nil, the local store will be put in the application support directory.
* @param containerIdentifier The identifier of the ubiquity container to use for the ubiquitous store. If nil, the entitlement's primary container identifier will be used.
* @param storeConfiguration The persistence model's configuration to load the store with. If nil, the default configuration is used.
* @param storeOptions Additional persistence options that the stores should be initialized with. If nil or empty, no options will be added to those necessary to load the store.
* @param delegate The application controller that will be handling the application's persistence responsibilities.
*/
- (id)initStoreNamed:(NSString *)contentName withManagedObjectModel:(NSManagedObjectModel *)model localStoreURL:(NSURL *)localStoreURL
containerIdentifier:(NSString *)containerIdentifier storeConfiguration:(NSString *)storeConfiguration storeOptions:(NSDictionary *)storeOptions
delegate:(id<UbiquityStoreManagerDelegate>)delegate;
I don't think I need different stores. The migration of the store works well on the device itself. But, currently if one device updates, the sync doesn't work anymore between different model versions (of course!).
So, as soon as a device uses a newer NSManagedObjectModel (app update) I want to force all other devices to update to the new app version too first. I want them to recognize this situation, to keep the sync by using iCloud and not to loose any data.
Do you see the possibility to force devices with older model versions to update to the most current version as soon as one device is using the current model version? (Without destroying sync or losing data)
Sure, set a value in the ubiquitous key-value store, and check for this value in the other apps. If the value is seen, block the user from using the app and tell them to update first. Of course, this will not work for existing installs of your app. But this is all rather beyond the scope of USM. The best USM can do for you is keep everybody running by maintaining an old and a new store which obviously won't sync with one another.
Our app uses UbiquityStoreManager to sync data between different devices. Until now our Core Data data model hasn't changed yet. But we're planning to release a new version which will ship with a new data model. Unfortunately lightweight migration is not feasible and we're having implemented our custom migration policy. We know that iCloud only supports lightweight migration.
What is the recommended way of updating our app, esp. if our customers are already using iCloud to sync data between different devices (using the old data model)?