Cocoa OS X and iOS iCloud Coredata sync - ios

I have an app for iOS and OSX which uses iCloud for syncing Coredata. In iOS its working well i think. The problems comes with the OSX version. The code used in the two versions is practically the same.
I have this in my AppDelegate:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"myStore.sqlite"];
NSURL *cloudRootURL=[fileManager URLForUbiquityContainerIdentifier:nil];
NSString *pathToCloudFile = [[cloudRootURL path]stringByAppendingPathComponent:#"Documents"];
pathToCloudFile = [pathToCloudFile stringByAppendingPathComponent:#"myAppCloudLogs1"];
NSURL *cloudURL = [NSURL fileURLWithPath:pathToCloudFile];
NSString *cloudStoreTitle = #"myStoreCloud";
NSDictionary *options = #{NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES,
NSPersistentStoreUbiquitousContentURLKey: cloudURL,
NSPersistentStoreUbiquitousContentNameKey: cloudStoreTitle};
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:#selector(processStoresWillChange:)
name:NSPersistentStoreCoordinatorStoresWillChangeNotification
object:_persistentStoreCoordinator];
[notificationCenter addObserver:self
selector:#selector(processStoresDidChange:)
name:NSPersistentStoreCoordinatorStoresDidChangeNotification
object:_persistentStoreCoordinator];
[notificationCenter addObserver:self
selector:#selector(processContentChanges:)
name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:_persistentStoreCoordinator];
return _persistentStoreCoordinator;
}
In both applications, when are started I can see the logs stored in the documents directory of the iCloud drive. There are 2 folders, 1 with my name (mac) and one with mobile simulator. When i create a new record in the simulator i can see new transaction log created in the simulator folder. But this change is not being reflected at my os x app. I think the transaction logs are not being replicated to other devices. Each device is only listening for changes in its folder. How can i do so each device listen for changes at others?
Is there any way so all the transaction logs are saved at the same folder for all devices?
When running the os x app i get this error message:
[PFUbiquitySetupAssistant canReadFromUbiquityRootLocation:]_block_invoke690(1489): CoreData: Ubiquity:
Attempting to download Peers hit a serious error for peers to download Error Domain=BRCloudDocsErrorDomain Code=5
No document at URL UserInfo=0x600000472f40 {NSDescription=No document at URL,
NSFilePath=/Users/myName/Library/Mobile Documents/iCloud~myGroup~myApp/Documents/myAppCloudLogs1/.DS_Store, NSUnderlyingError=0x600000251340 } with userInfo {
NSDescription = "No document at URL";
NSFilePath = "/Users/myName/Library/Mobile Documents/iCloud~myGroup~myApp/Documents/myAppCloudLogs1/.DS_Store";
NSUnderlyingError = "Error Domain=NSPOSIXErrorDomain Code=2 UserInfo=0x600000472fc0 {NSDescription=No such file or directory}";
}
Why am i getting this error?? What is .DS_Store file? In my ICloud Drive folders i only see .cdt files.
Need help please. Thanks in advance.

Related

Migrating iCloud to local persistent store

I am running out of ideas how could I possibly migrate the iCloud store to local store.
From one side I get crash with message:
The specified persistent store was not found
on the other side
NSUnderlyingException = "Can't add the same store twice"
The point is there is no clear tutorial how to migrate stores (Or at least I can't find). Everything I found so far was pieces of information spread across net and couldn't make very much sense.
This is my code:
- (NSPersistentStoreCoordinator *) cloudPersistentStoreCoordinator {
self.storeURL = [[MMNUtilities localDocumentsURL] URLByAppendingPathComponent:#"myapp.sqlite"];
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
NSDictionary *storeOptions = #{NSPersistentStoreUbiquitousContentNameKey: #"myapp"};
NSError *error = nil;
self.persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:self.storeURL
options:storeOptions
error:&error];
if (error) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
- (BOOL) didMigrateiCloudStoreToLocalStore {
NSError *error = nil;
self.persistentStoreCoordinator = [self cloudPersistentStoreCoordinator];
NSDictionary *storeOptions = #{NSPersistentStoreUbiquitousContentNameKey: #"myapp",
NSPersistentStoreRemoveUbiquitousMetadataOption : #YES};
NSPersistentStore *localStore = [self.persistentStoreCoordinator migratePersistentStore:self.persistentStore <<< Exception happens here
toURL:self.storeURL
options:storeOptions
withType:NSSQLiteStoreType
error:&error];
if (error) {
NSLog(#"Error: %#", error.description);
[[NSNotificationCenter defaultCenter] postNotificationName:HnHCoreDataPersistentStoreMigrationFailed object:self];
return NO;
}
return [self reloadStore:localStore];
}
I got following message in console:
CoreData: error: -addPersistentStoreWithType:SQLite configuration:PF_DEFAULT_CONFIGURATION_NAME URL:file:///var/mobile/Containers/Data/Application/EFC750F6-D10E-4B8A-9F83-C77621218DB7/Documents/myapp.sqlite options:{
NSPersistentStoreRemoveUbiquitousMetadataOption = 1;
NSPersistentStoreUbiquitousContentNameKey = myapp;
"_NSNotifyObserversOfStoreChange" = 0;
} ... returned error Error Domain=NSCocoaErrorDomain Code=134080 "The operation couldn’t be completed. (Cocoa error 134080.)" UserInfo=0x15deee80 {NSUnderlyingException=Can't add the same store twice} with userInfo dictionary {
NSUnderlyingException = "Can't add the same store twice";
}
Any help will be appreciated.
You need to create a new local store with a different name.

How to enable iCloud for Core Data?

This is the first time I'm trying to make this work. I'm following the iCloud Programming Guide for Core Data, the "Using the SQLite Store with iCloud" section, and in AppDelegate I have:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MyApp.sqlite"];
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
// To enable iCloud
NSDictionary *storeOptions = #{NSPersistentStoreUbiquitousContentNameKey: #"MyAppCloudStore"};
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:storeOptions error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
Previously, I enabled iCloud services for this App ID, create the corresponding provisioning, and turn on the iCloud services in Xcode's capabilities (iCloud Documents and default container).
According to the iCloud Programming Guide for Core Data, at this point:
Test: Run the app on a device. If Core Data successfully created and configured an iCloud-enabled persistent store, the framework logs a message containing “Using local storage: 1,” and, later, another message containing “Using local storage: 0”.
I run the app on an iPhone, and persistentStoreCoordinator is retrieved, but I see nothing in Xcode's debug area.
What am I missing?
Thanks?
I found the problem: [[NSFileManager defaultManager] ubiquityIdentityToken] was returning nil, and it was because I had my device not updated to iCloud Drive.
I found the response in this post.

Migrating an iCloud Store to a Local Store and making sure the data is there through each app launch

Based on the question here: Migrate iCloud data to Local store and stopping iCloud from still responding regard moving an iCloud store over to a local store and making sure the iCloud notifications are disabled, I have the next scenario that I am stuck on.
Issue
Right now, when the user runs the app on the first device, they're asked at the start if they want to enable iCloud. If they select yes, the data is migrated over to iCloud. If the user connects in a second device, they're asked if they want to use iCloud at the start and if they select yes, data from the first device is synchronised across.
If the user on the second device decides they don't want to use iCloud anymore, they can navigate and turn off iCloud within the app for that device specifically. This in the back-end will migrate their data from the iCloud store to the Local Store. From the users point of view, all of their data is there (whether it's stored in the cloud or local doesn't matter to the user at this point).
The issue is when I migrate my data across, it successfully migrates over to the local iCloud store and successfully stops listening for iCloud notifications. That aspect works and that's in the stack overflow question that I previously asked (Migrate iCloud data to Local store and stopping iCloud from still responding).
The specific issue is that when the user re-launches the app, the app is now empty with no data. This is of course not the desired effect.
For completeness, the "migration code" is based in the other stack overflow question but I'm pasting it here for convenience:
- (void)migrateiCloudStoreToLocalStore {
NSLog(#"Migrate iCloudToLocalStore");
NSPersistentStore *store = self.persistentStoreCoordinator.persistentStores.lastObject;
//NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Envylope.sqlite"];
NSURL *storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
NSLog(#"Current Store URL (before iCloud to Local migration): %#", [storeURL description]);
NSDictionary *localStoreOptions = nil;
localStoreOptions = #{ NSPersistentStoreRemoveUbiquitousMetadataOption : #YES,
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES};
NSPersistentStore *newStore = [self.persistentStoreCoordinator migratePersistentStore:store
toURL:storeURL
options:localStoreOptions
withType:NSSQLiteStoreType error:nil];
[self reloadStore:newStore];
}
- (void)reloadStore:(NSPersistentStore *)store {
NSLog(#"Reload Store");
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Envylope.sqlite"];
NSDictionary *localStoreOptions = nil;
localStoreOptions = #{ NSPersistentStoreRemoveUbiquitousMetadataOption : #YES,
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES};
if (store) {
[self.persistentStoreCoordinator removePersistentStore:store error:nil];
}
[self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:localStoreOptions
error:nil];
storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
NSLog(#"Current Store URL (after iCloud to Local migration): %#", [storeURL description]);
NSLog(#"Done reloading");
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:#"MigratedFromiCloudToLocal"];
[[NSUserDefaults standardUserDefaults]synchronize];
All of the magic happens in the persistentStoreCoordinator.. it's messy, but I need to get this part working and then this can be cleaned up:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Envylope.sqlite"];
NSError *error = nil;
NSURL *iCloud = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil];
NSDictionary *options = nil;
if ((iCloud) && (![[NSUserDefaults standardUserDefaults] boolForKey:#"iCloudOn"]) && (![[NSUserDefaults standardUserDefaults]boolForKey:#"OnLatestVersion"]))
{
NSLog(#"In the persistent store, iCloud is enabled in the app device but not yet in the app and not on the latest version");
options = #{ NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES};
}
else if ((iCloud) && ([[NSUserDefaults standardUserDefaults] boolForKey:#"iCloudOn"]) && ([[NSUserDefaults standardUserDefaults]boolForKey:#"OnLatestVersion"]))
{
NSLog(#"In the persistent store, iCloud is enabled, we're using iCloud from the Tutorial and we're on the latest version");
NSURL *cloudURL = [self grabCloudPath:#"iCloud"];
options = #{ NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES,
NSPersistentStoreUbiquitousContentURLKey: cloudURL, NSPersistentStoreUbiquitousContentNameKey: #"EnvyCloud"};
}
else if ((iCloud) && (![[NSUserDefaults standardUserDefaults] boolForKey:#"iCloudOn"]) && ([[NSUserDefaults standardUserDefaults]boolForKey:#"OnLatestVersion"]))
{
NSLog(#"In the persistent store, iCloud is enabled, we're on the latest version, btu we're not using icloud in the App");
options = #{ NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES};
}
else
{
NSLog(#"iCloud is just not enabled");
options = #{ NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES};
}
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
//abort();
}
return _persistentStoreCoordinator;
}
So in the scenario where the user enables iCloud in the app and then decides NOT to have iCloud anymore on this particular device, the iCloud notifications get removed, the store is migrated from the iCloud Store to the local store and a NSUserDefaults is set. On the next launch of the app.. the 3rd if statement evaluates as true in the persistentStoreCoordinator which is correctly saying we're on the latest version, iCloud is enabled (in the device) but not in the app, but then it shows the app with absolutely no entries whatsoever, kind of like starting fresh.
How do I overcome this and return the store that was just recently migrated?
Any thoughts would seriously be greatly appreciated.
No data upon app launch points to the persistent store coordinator.
Looks like the evaluation for the options dictionary is fine, but in either outcome you're always setting up the coordinator with the same persistent store URL.
Likewise, in the migration routine, you're migrating the persistent store object, but with the same URL. That can't work, as that's where the actual files are saved. You need a different URL for the local store and for the iCloud store, then you can correctly migrate the data across and choose to delete the URL you no longer need (after removing the store from the coordinator).
Setup the coordinator with the respective URL, depending on the outcome of your evaluation - and hopefully - you should see your data upon app launch.

Migrating existing Core Data to iCloud

I have a simple application which is a UITableView that gets populated by the user filling in some UITextFields in a different view. This information gets saved to CoreData and the UITableView gets updated using NSFetchedResultsController.
I'm now introducing iCloud synching into my environment. With reference to a previously asked question: Existing Core Data Database Not Uploading to iCloud When Enabling iCloud On My App , I am still having issues but it was too messy to update that question with my new code. I am referring specifically to the WWDC 2013 CoreData Sessions, as well as this. Because my app is iOS 7 only. I'm fairly new to iCloud development and am an intermediate programmer.
I am having some great difficulty migrating my existing data to iCloud when I update from the App Store (non-iCloud) version to the development (iCloud) version. New data syncs across perfectly.
I understand that I need to essentially take my existing store without iCloud and migrate it across to iCloud but it's just not working out for me.
Here's some code to illustrate what I'm working on:
Update
I have gone through and thought about this and have removed code that was redundant.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Planner.sqlite"];
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *url = [fm URLForUbiquityContainerIdentifier:nil];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (url)
{
NSLog(#"iCloud is enabled");
NSDictionary *options = #{
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES,
};
NSPersistentStore *localStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
[_persistentStoreCoordinator migratePersistentStore:localStore toURL:[self iCloudURL] options:[self iCloudStoreOptions] withType:NSSQLiteStoreType error:&error];
}
else
{
NSLog(#"iCloud is not enabled");
NSDictionary *options = #{
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES
};
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self iCloudURL] options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"Reload" object:self userInfo:nil];
});
return _persistentStoreCoordinator;
}
I am no longer calling the migrateLocalStoreToiCloud method but it is here for reference:
/*-(void)migrateLocalStoreToiCloud
{
//assuming you only have one store.
NSPersistentStore *store = [[_persistentStoreCoordinator persistentStores] firstObject];
NSPersistentStore *newStore = [_persistentStoreCoordinator migratePersistentStore:store
toURL:[self iCloudURL]
options:[self iCloudStoreOptions]
withType:NSSQLiteStoreType
error:nil];
[self reloadStore:newStore];
}
*/
The storeURL, storeOptions, iCloudURL and iCloudStoreOptions code is:
- (NSURL *)iCloudURL
{
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *url = [fm URLForUbiquityContainerIdentifier:nil];
if (url) {
NSLog(#"iCloud access at %#", url);
} else {
NSLog(#"No iCloud access");
}
return url;
}
-(NSURL *)storeURL{
return [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Planner.sqlite"];
}
-(NSDictionary *)storeOptions{
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
return options;
}
-(NSDictionary *)iCloudStoreOptions{
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:#"PlannerStore" forKey:NSPersistentStoreUbiquitousContentNameKey];
return options;
}
Problem
When I run this code exactly as it is, I am not presented in the console with Using Local Storage : 1 and 0 at all, though the data is there.
If I change the persistentStoreCoordinator where it first adds the persistentStore to use [self iCloudStoreOptions] as the options, the Using Local Storage 1 and 0 displays, but the data does not on the device.
I'm following the guidance here and I have tried multiple variations of my code including not removing any persistentStore in the reloadStore method but I am completely stuck.
I have read so many posts but it seems that I just cannot find someone who is migrating data from a non-iCloud version to an iCloud version and with examples I have found, there's no code.
I have looked into this and while it is a great code set, I've downloaded the code and followed those guidelines where it doesn't remove any persistentStore but it still wouldn't work for me. I can't imagine what I'm trying to achieve is very complicated. I simply need to take the existing non-iCloud data and migrate it over to iCloud.
Update
With reading Apple's guide : https://developer.apple.com/LIBRARY/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/doc/uid/TP40013491-CH3-SW2 I can see that my migrateLocaltoiCloud method is currently wrong with the removing of the persistentStore, etc, but I can't figure out how to fix it. If I call this from the persistentStoreCoordinator, will it somehow interfere with the DidChangeNotification?
I'm really stuck on this and I would appreciate any guidance into the right direction
I am providing an answer here to my question because it's clearer than updating the question and after a lot of debugging, I have this working, to some extent.
With debugging the addPersistentStore and migratePersistentStore lines of code, I came up with:
NSPersistentStore *localStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
NSLog(#"The localStore is %#", localStore);
NSPersistentStore *migratedStore = [_persistentStoreCoordinator migratePersistentStore:localStore toURL:[self iCloudURL] options:[self iCloudStoreOptions] withType:NSSQLiteStoreType error:&error];
NSLog(#"The migrationStore is %#", migratedStore);
The NSLog value of localStore is: The localStore is <NSSQLCore: 0x13451b100> (URL: file:///var/mobile/Applications/DDB71522-C61D-41FC-97C7-ED915D6C46A4/Documents/Planner.sqlite)
The NSLog value of migratedStore is: (null)
With debugging, I could see essentially the same thing, that migrateStore was always null.
I changed the code slightly:
NSPersistentStore *migratedStore = [_persistentStoreCoordinator migratePersistentStore:localStore toURL:storeURL options:[self iCloudStoreOptions] withType:NSSQLiteStoreType error:&error];
For the URL to be the storeURL and suddenly, everything started working, where storeURL:
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Planner.sqlite"];
My outputs were:
The localStore is <NSSQLCore: 0x14ee09b50> (URL: file:///var/mobile/Applications/CC0F7DA0-251F-46D6-8E43-39D63062AED2/Documents/Planner.sqlite)
[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](771): CoreData: Ubiquity: mobile~5BD59259-7758-42FB-986F-DDD173F75ED3:EnStor
The migrationStore is <NSSQLCore: 0x157e260b0> (URL: file:///var/mobile/Applications/A08D183D-ECD4-4E72-BA64-D21727DE7A3E/Documents/CoreDataUbiquitySupport/mobile~CB6C3699-8BF1-47DB-9786-14BCE1CD570A/EnStor/771D2B0B-870A-428E-A9A8-5DAE1295AF53/store/Planner.sqlite)
The Using Local Store went from 1 to 0 and my data from the App Store version of the app continued to be there through the migration to the new version. This was the output the first time I ran the app after the upgrade.
This is great news.
Every subsequent time I ran the app though, the data continued to migrate and so I would end up with duplicate results.
The issue also is the fact that when adding a new device, it doesn't pull down the information to the new device.
I don't quite understand why using storeURL as the url for migratePersistentStore worked?
I also don't want each new device to basically add a new persistent store if one already exists and I don't know how I would get around this and also I don't want the migration to occur again and again. It should only occur the one time.
I'm getting there, but still a lot of work to be done!

Core Data Automatic Lightweight Migration failing after moving sqlite file

in my app I've used Core Data Automatic Lightweight Migration fine for multiple versions. About a year ago I implemented iOS File Sharing so I moved the sqlite database to the /Library folder rather than the /Documents directory to keep it hidden. I haven't added another Core Data version since that time.
Now when I try to add another Entity and increase the model version I get the following error (truncated to show just the tail end):
"_NSAutoVacuumLevel" = 2;
}, reason=Can't find model for source store}
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason:
'This NSPersistentStoreCoordinator has no persistent stores.
It cannot perform a save operation.'
I've verified that the .sqlite file exists on disk as expected. I've been troubleshooting for a few days and it seems if I move the sqlite file back to the /Documents directory the migration works OK.
Below is the code for the persistent store coordinator:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self libraryDocumentsDirectory] stringByAppendingPathComponent: #"myappdb.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
//Pass options in for lightweight migration....
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:options error:&error]) {
/*Error for store creation should be handled in here*/
NSLog(#"ERROR IN MIGRATION........%#", error);
}
return persistentStoreCoordinator;
}
- (NSString *)libraryDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
}
Has anyone encountered this situation before?
Thanks in advance for your help.
"Now when I try to ad another model entity and increase the version number..."
You need to create a new model version before you create a new entity or make changes to existing entities. Make sure your changes were not made in the old model version by mistake.
After creating version and marking it as a current version you have to add an extra value in options which is used to add PersistentStore and then you go( I am not sure about other iOS version but yeah it will definitely work on iOS 7).
-(NSManagedObjectModel *)managedObjectModel
{
if (managedObjectModel != nil)
{
return managedObjectModel;
}
managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return managedObjectModel;
}
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil)
{
return persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ABC.sqlite"];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] ini tWithManagedObjectModel:[self managedObjectModel]];
//Creating Lightweight migration.
NSDictionary *options =
#{
NSMigratePersistentStoresAutomaticallyOption:#YES
,NSInferMappingModelAutomaticallyOption:#YES
,NSSQLitePragmasOption: #{#"journal_mode": #"DELETE"}
};
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}

Resources