Reputation: 16825
I'am using the new iOS 7 API for syncing Core Data with iCloud. It's a pretty easy and straightforward API, but I can't find a working way to disable it and use the local storage again. Without dataloss.
I'am creating my iCloud persistantStore
like this. It's working like a charm.
[[context persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:[self iCloudFilePath]] options:@{ NSPersistentStoreUbiquitousContentNameKey: @"Favorite" } error:&error];
However, I try to use the new migration API, for migrating the store from an iCloud store to an local store like this:
Method 1 uses *icloudps as store and method 2 use *ps as store.
NSPersistentStore *icloudps = [[[context persistentStoreCoordinator]
persistentStores] objectAtIndex:0];
NSPersistentStore *ps = [[context persistentStoreCoordinator]
addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:[icloudps URL] options:nil error:&error];
[[context persistentStoreCoordinator] migratePersistentStore:icloudps
toURL:[NSURL fileURLWithPath:[self filePath]]
options:@{ NSPersistentStoreRemoveUbiquitousMetadataOption: @YES }
withType:NSSQLiteStoreType error:&error];
Method 1 results in this crash:
Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0xd000000000080002 x-coredata://153BBFEA-0319-4F10-AEA4-1DA12A21BFFF/Favorite/p2>''
Method 2 in this:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'nil is not a valid persistent store'
I have no idea how to get this working. Hopefully someone can help.
Upvotes: 0
Views: 1173
Reputation: 8988
EDIT
I have just posted a sample iOS library style Core Data app which includes iCloud integration. The app includes a Settings Bundle for the user to toggle "Use iCloud" preference settings and will migrate the store to and from iCloud depending on the users settings.
Download from the link below - sorry about the documentation - will get around to that at some point but it works much the same way as the UIManagedDocument example.
http://ossh.com.au/design-and-technology/software-development/
END EDIT
If its any help at all here is the method I use on OS X to save another copy of an iCloud synced Core Data document (in response to user selecting the Save As menu option). For the most part iOS should work in the exact same manner. Also bear in mind you may have to close and reopen the document once the migration is completed - I seem to recall some issue if I did not do that.
/*! This method is used to build another local Core Data document, usually in response to the user selecting the 'Save As' menu option. The document is NEVER iCloud enabled when we do this and the User can select the 'Share in iCloud' menu option once Save As is done to make the file available to other devices via iCloud.
@param newURL The URL where the new file is to be created.
@param typeName The type(SQLite, Binary or XML) of file to use for the new store.
@param error Upon return contains the error if one was encountered
@return Returns YES if the new store was successfully created and NO if not.
*/
- (bool)buildNewStoreAtURL:(NSURL*)newURL type:(NSString *)typeName error:(NSError **)error {
//FLOG(@"buildNewStoreAtURL:type:error: called");
NSError *myError;
// We only have one store so get it
NSPersistentStore *currentStore = [self.managedObjectContext.persistentStoreCoordinator.persistentStores objectAtIndex:0];
// Get any options it has, we assume we need to keep most of them
NSDictionary *currentOptions = currentStore.options;
NSMutableDictionary *newOptions = [[NSMutableDictionary alloc] initWithDictionary:currentOptions];
// Make sure we don't use WAL mode, it has issues
[newOptions setObject:@"DELETE" forKey:@"JOURNAL"];
// Remove any iCloud options (this one includes the unique iCloud UUID)
[newOptions removeObjectForKey:NSPersistentStoreUbiquitousContentNameKey];
// Remove Core Data ubiquity metadata
[newOptions setObject:[NSNumber numberWithBool:YES] forKey:NSPersistentStoreRemoveUbiquitousMetadataOption];
NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator;
// Now migrate the store to the new location
NSPersistentStore *newStore = [psc migratePersistentStore:currentStore toURL:newURL options:newOptions withType:typeName error:&myError];
// Now check it was successful
if (newStore) {
// Now set up our custom metadata so we can determine if it has been synced in iCloud next time we open it
// We have to know this in order to pass in the correct options to the PSC
NSDictionary *dict = [self getiCloudMetaDataForStore:[psc metadataForPersistentStore:newStore] iCloud:NO ubiquityName:nil];
[psc setMetadata:dict forPersistentStore:newStore];
return YES;
}
else {
FLOG(@" problem creating new document");
FLOG(@" - error is %@, %@", myError, myError.userInfo);
*error = myError;
return NO;
}
}
Upvotes: 1