views:

715

answers:

4

I have an iphone app that uses Core Data to do storage. I have successfully deployed it, and now I'm working on the second version. I've run into a problem with the data model that will require a few very simple data transformations at the time that the persistent store gets upgraded, so I can't just use the default inferred mapping model.

My object model is stored in an .xcdatamodeld bundle, with versions 1.0 and 1.1 next to each other. Version 1.1 is set as the active version. Everything works fine when I use the default migration behavior and set NSInferMappingModelAutomaticallyOption to YES. My sqlite storage gets upgraded from the 1.0 version of the model, and everything is good except for, of course, the few transformations I need done.

As an additional experimental step, I added a new Mapping Model to the core data model bundle, and have made no changes to what xcode generated. When I run my app (with an older version of the data store), I get the following

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Object's persistent store is not reachable from this NSManagedObjectContext's coordinator'

What am I doing wrong? Here's my code for to get the managed object model and the persistent store coordinator.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

 if (_persistentStoreCoordinator != nil) {
  return _persistentStoreCoordinator;
 }

 _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

 NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"gti_store.sqlite"]];

 NSError *error;
 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]) {
  NSLog(@"Eror creating persistent store coodinator - %@", [error localizedDescription]);
 }    

 return _persistentStoreCoordinator;
}


- (NSManagedObjectModel *)managedObjectModel {

 if(_managedObjectModel == nil) {

  _managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
  NSDictionary *entities = [_managedObjectModel entitiesByName];

        //add a sort descriptor to the 'Foo' fetched property so that it can have an ordering - you can't add these from the graphical core data modeler
  NSEntityDescription *entity = [entities objectForKey:@"Foo"]; 
  NSFetchedPropertyDescription *fetchedProp = [[entity propertiesByName] objectForKey:@"orderedBar"];
  NSSortDescriptor* sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES] autorelease];
  NSArray* sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
  [[fetchedProp fetchRequest] setSortDescriptors:sortDescriptors];
    }
    return _managedObjectModel;
}
A: 

I've got the same error message. I use multiple threads and multiple managedObject context. How comes this message? I can't find the problem anywhere in the web :/

thomask
You probably need to read the docs on how to use Core Data in a multi-threaded application. Chances are you are breaking those rules.
Marcus S. Zarra
A: 

First, turn off the automatic migration if you are having a mapping model, fair chance they are colliding. Once you have done that, confirm that the error is gone.

Marcus S. Zarra
A: 

I haven't thought this out very carefully, it's just an observation as I was having the same problem, and I too have found very few references to this error on the web.

In my case the problem was that I had setup one of my application's objects to observe

NSManagedObjectContextObjectsDidChangeNotification like so

        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(observeContextSave:)
                                                 name:NSManagedObjectContextDidSaveNotification
                                               object:nil];


- (void) observeContextSave:(NSNotification*) notification {
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];}

Once I moved this code so that is was executed after the migration, the error went away.

Anyway. I'm sure your circumstances are different. But it may help to think about what observations you have setup on notifications from your managedObjectContext.

Update: Having thought about this a bit more, I guess it happens because multiple persistent stores are created during migration, which means that NSManagedObjectContextDidSaveNotification will be sent from a context with a different persistent store to the context that is sent mergeChangesFromContextDidSaveNotification.

Ira Cooke
That was it - I discovered this several months ago after literally days of staring at the same lines of code. I just had a eureka moment, and it worked.If you had answered this last november, I would have offered to buy you a case of whatever your favorite beverage is. :>
dpratt
Thanks for confirming that this was what happened to you too. It would be great to know the underlying mechanics of why this happens though. I haven't fully thought it through, and don't really know core-data internals well enough to "get it".
Ira Cooke
A: 

I had similar issue when persistent store initialization was performed from secondary thread. After I forced initialization in primary thread the problem has gone. Weird.

Sergiy Salyuk