0

I've been hunting for a solution for the last four hours and I am posting in desperation. My app was working perfectly on the simulator, my iPhone, and my ipad until I added an attribute to one of my Data Models.

My iPhone application uses Core Data and iCloud. In the AppDelegate, I create the managedObjectModel by merging two models. Everything seems fine until I try to save the ManagedObjectContext. That's when it crashes with:

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.'

This does not happen on the simulator.

I have tried:

  • Project->Clean Build Folder
  • Project->Clean
  • Deleting the app from my device
  • Deleting the iCloud data from my iCloud back up
  • reboot computer
  • changed the ".momd" to ".mom" and back again (read about it in another question)

Thanks for the help.

EDIT to add code:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
    return __persistentStoreCoordinator;
}

__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];    
NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;

// TODO: Set up iCloud in another thread:
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *dataFileName = [NSString stringWithFormat:@"%@.sqlite", APP_TITLE_NO_SPACES];

NSString *iCloudDataDirectoryName = @"Data.nosync";
NSString *iCloudLogsDirectoryName = @"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];        
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];

if (iCloud) {
    NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
    if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
        NSError *fileSystemError;
        [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] 
               withIntermediateDirectories:YES 
                                attributes:nil 
                                     error:&fileSystemError];
        if(fileSystemError != nil) {
            NSLog(@"Error creating database directory %@", fileSystemError);
        }
    }

    NSString *iCloudData = [[[iCloud path] 
                             stringByAppendingPathComponent:iCloudDataDirectoryName] 
                            stringByAppendingPathComponent:dataFileName];

    NSLog(@"iCloudData = %@", iCloudData);

    NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
                             CLOUD_CONTAINER_IDENTIFIER, NSPersistentStoreUbiquitousContentNameKey,
                             iCloudLogsPath, NSPersistentStoreUbiquitousContentURLKey, nil];

    [psc lock];
    [psc addPersistentStoreWithType:NSSQLiteStoreType 
                      configuration:nil 
                                URL:[NSURL fileURLWithPath:iCloudData] 
                            options:options 
                              error:nil];
    [psc unlock];
} else {
    NSLog(@"iCloud is NOT working - using a local store");
    NSMutableDictionary *options = [NSMutableDictionary dictionary];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];

    [psc lock];

    [psc addPersistentStoreWithType:NSSQLiteStoreType 
                      configuration:nil 
                                URL:localStore 
                            options:options 
                              error:nil];
    [psc unlock];
}
__persistentStoreCoordinator = psc;

[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ICLOUD_SOMETHING_CHANGED object:nil];

return __persistentStoreCoordinator;

}

Blamdarot
  • 3,317
  • 1
  • 18
  • 15
  • Due to time constraints, I opted to reset my device. The app is working as expected. I'd still like to find a solution, because this is a problem that could easily happen in the future. – Blamdarot Apr 26 '12 at 20:27

1 Answers1

0

Usually, it should okay after you deleted the program data. However, error indicates, that you do not have an inconsistency but simply no store at all. Assumption: you do not re-initiate it in case of a fault. Maybe, the following code can be useful:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator

{
    if (__persistentStoreCoordinator != nil) {
        return __persistentStoreCoordinator;
    }
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"myApp.sqlite"];

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // Error, erase data
        [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
        NSLog(@"store cleaned");
        __persistentStoreCoordinator = nil;
        return [self persistentStoreCoordinator];
    }    
    return __persistentStoreCoordinator;
} 
Matthias
  • 8,018
  • 2
  • 27
  • 53
  • Thank you for your response. Unfortunately, I'm not sure how to integrate that into my code. My persistentStoreCoordinator getter method has a lot of iCloud code. I'll add my code to my orignal post. – Blamdarot Apr 26 '12 at 07:31