1

I never had any problems with Xcode3, but with Xcode4 I'm getting Apple's code failing approx 1 time in 3 when I update a core data model, with the dreaded "Persistent store migration failed, missing source managed object model." error.

Here's my setup (how I configured the project to auto-migrate):

  1. NSPersistentDocument, from Apple's template
  2. Override Apple's model-loading method, and the ONLY thing I do is to provide the two flags in the storeOptions Dictionary, which turn on auto-migration
-(BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error
{

    NSMutableDictionary *newOptions = nil;

    if( storeOptions != nil )
        newOptions = [NSMutableDictionary dictionaryWithDictionary:storeOptions];
    else
        newOptions = [NSMutableDictionary dictionary];

    [newOptions setValue:@"YES" forKey:NSMigratePersistentStoresAutomaticallyOption];
    [newOptions setValue:@"TRUE" forKey:NSInferMappingModelAutomaticallyOption];

    BOOL success = FALSE;

    success = [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:newOptions error:error];

    return success;
}

Here's the process I've been using (which is already working around 1 bug in Xcode4!)

  1. Select the model (named "something.xcdatamodel" in Xcode4, with a twisty on the left)
  2. Go to Editor menu, select "Add new model version..."
  3. Name the new version 1 integer higher than last - e.g. if previous was "4" name the new one "5"
  4. In the right-hand pane, change the current model version to the newly-created one
  5. workaround for XCode4 bug: select any file, then select the newly-created model. If you do not, Xcode shows the selection on the newly-created model, but will edit the previous model instead, which definitely corrupts everything in CoreData
  6. Edit your model; in this case, I'm adding a new attribute to an existing entity
  7. Save. Build. Run. ... CRASH.

Except, as I said, approx 2 times in 3 this works correctly. Once it works once, it's (obviously) fine - the lightweight migration is complete, the next save saves in the new model version.

So I'm guessing there's something I'm doing wrong in the above steps, but I've been through the docs 5 or 6 times and can't see anything obvious. Doesn't help that NSPersistentDocument docs are all out of date - but I've done lightweight migration on iPhone lots of times too, so I'm reasonably confident with doing this, and it seems right to me.


Other things I've tried/checked: - iPhone Core Data Lightweight Migration Cocoa error 134130: Can't find model for source store (nope; only the root xcdatamodel was being included)

Community
  • 1
  • 1
Adam
  • 32,900
  • 16
  • 126
  • 153
  • Does the crash produce any errors? – TechZen Jul 18 '11 at 19:10
  • Are you trying to migrate a development build? – TechZen Jul 18 '11 at 19:11
  • Are you using the same copy of the store over and over again or are you starting with a fresh copy each time? – TechZen Jul 18 '11 at 19:29
  • Only the "persistent migration failed error" – Adam Jul 25 '11 at 13:01
  • How can you migrate a store that is "a fresh copy"? Surely that's impossible - there would be nothing to migrate? – Adam Jul 25 '11 at 13:01
  • Migration is intended to work on an end user's existing database. When you are in development, you want to have a canonical copy of the test store that you can use for the bases of every migration test. If you don't, you end up trying to migrate a store that has been migrated repeatedly and often incompletely or incorrectly. Once the store is corrupted by a failed migration, nothing works. When testing migration start with a fresh copy of the canonical store each time you run the migration. – TechZen Jul 25 '11 at 16:25
  • So ... you're saying I should put in source-control one copy of the store for each model version? And then with each update/release, cross-test it against all the SCM'd versions? That sounds like a good idea - I do that with major releases, but haven't bothered when doing it with private beta tests – Adam Jul 26 '11 at 12:04
  • My problems on this particular project recur even when I frequently re-create new stores. I'm on model version 7 now, and I've had problems with 3->4, 4->5, 3->5, 6->7 :( – Adam Jul 26 '11 at 12:05
  • Okay, at least you have eliminated corruption generated in development as a source of the error. – TechZen Jul 26 '11 at 15:50

3 Answers3

3

Use [NSNumber numberWithBool:YES] not @"YES" or @"TRUE".

tiago
  • 22,602
  • 12
  • 72
  • 88
lupinglade
  • 481
  • 5
  • 11
  • Why would that make any difference? The [boolValue] of an NSString is built-in, and evaluates "YES" exactly the same as the code you provided. – Adam Nov 22 '12 at 07:08
  • [NSNumber numberWithBool:x] will not call boolValue on your NSString, a boolean value is expected. It will always evaluate to true. Ie. numberWithBool:@"NO" will still theoretically be YES (true). – lupinglade Dec 26 '12 at 21:45
0

I was getting super-confused but this, and it WASN'T working.. because I was assuming that the method would already HAVE a "store options" dictionary.. I just needed to check for it's existence before i set the aforementioned options…

-(BOOL)configurePersistentStoreCoordinatorForURL:       (NSURL*)u
                                          ofType:    (NSString*)t
                              modelConfiguration:    (NSString*)c
                                    storeOptions:(NSDictionary*)o 
                                           error:    (NSError**)e 
{  
 return [super configurePersistentStoreCoordinatorForURL:u
                                                  ofType:t
                                      modelConfiguration:c
                                            storeOptions:
    o ? [o dictionaryWithValuesForKeys:
         @[ NSMigratePersistentStoresAutomaticallyOption, @YES,  
            NSInferMappingModelAutomaticallyOption,       @YES]] 
      :  @{ NSMigratePersistentStoresAutomaticallyOption :@YES,
            NSInferMappingModelAutomaticallyOption       :@YES}
                                                  error:e];
}
Alex Gray
  • 16,007
  • 9
  • 96
  • 118
0

Since you have eliminated a corrupt development store as a source of the problem, I suspect the problem lays in Xcode 4.x which is buggy to say the least. A lot of people are reporting similar issues but no two problems seem exactly the same. It is probably a bug/s that only occur with specific data model setups so the problem will be very hard to track down.

You may simply have to abandon automatic migration and create an explicit migration map. It takes longer and introduces complexity into your code but it will always work.

If you have a shipping app and will be dealing with end user data in the wild, you do have a moral and business obligation to take the extra step to protect end user data.

TechZen
  • 64,370
  • 15
  • 118
  • 145
  • I think you may be right - there's a lot of obvious bugs in Xcode4's handling of CoreData. I'd just hoped there was something obvious *I* was doing wrong - that would be much better than having to "hope and wait" for Apple to fix it. – Adam Jul 28 '11 at 15:56