Основные данные не могут найти модель для исходного магазина - как выглядел мой старый магазин? - PullRequest
10 голосов
/ 27 августа 2010

Итак, во-первых, этот вопрос очень помог в достижении верного пути к версионированию рабочих данных ядра.Поэтому я добавил новую версию для своей модели, и теперь я пытаюсь заставить работать автоматическую миграцию, но у меня есть проблема.Я не могу вспомнить, как выглядела моя старая версия!Я пытаюсь запустить приложение на своем телефоне, но какое-то время пользовался симулятором и внес несколько изменений в схему.Версия на телефоне довольно давно.Поэтому каждый раз, когда я пытаюсь изменить старую версию на то, что, по моему мнению, находится на телефоне, я все равно получаю сообщение об ошибке «Не могу найти модель для источника».Я предполагаю, что это потому, что я неправильно понял старую схему.

Могу ли я узнать, как эта схема выглядит на телефоне?За исключением этого, как я могу просто стереть хранилище sqlite с телефона, чтобы я мог начать заново с версии 1?

Ответы [ 4 ]

13 голосов
/ 07 сентября 2012

Я целый день рвал на себе волосы из-за ошибки «Не могу найти модель для исходного магазина».Вот ответ от Learner2010 для googlers:

  • Хеш модели вашей базы данных sqlite ДОЛЖЕН соответствовать одной из мам или мам, созданных вашей xcdatamodel при создании приложения.Вы можете увидеть хеши в momd's VersionInfo.plist в комплекте встроенного приложения.Ниже приведен код для поиска хэша модели вашей базы данных.

  • Так что если вы измените свой xcdatamodel вместо создания новой версии в Xcode-> Editor-> Add Model Version ... тогда вашхеш модели будет другим, и addPersistentStoreWithType не сможет использовать вашу старую базу данных, которая использовала старую модель.Вот почему возникает ошибка «Не удается найти модель для хранилища исходного кода».

  • Что еще хуже, база данных sqlite хранится в чем-то вроде "/ private / var / mobile / Library/ Мобильные документы / YOU_APP_ID / Data.nosync / YOUR_DB.sqlite ", и это может остаться, даже если вы удалите приложение с устройства и переустановите его!Таким образом, вы будете думать, что с вашим кодом что-то не так, когда на самом деле у вас просто устаревшая база данных, которую нужно удалить.Обычно это происходит во время отладки, поэтому в любом случае в нем нет реальных данных.

  • Поэтому правильный рабочий процесс, позволяющий выполнять миграции в будущем, - это создание модели, запуск приложения для построения базы данных,а затем создавать новые версии модели в любое время, когда вам нужно внести изменения.Все будет "просто работать", если вы оставите изменения незначительными.Затем, когда вы будете готовы выпустить свое приложение, выберите окончательную модель и удалите остальные.Затем удалите вашу базу данных из "/ private / var / mobile / Library / Mobile Documents".Затем в будущих выпусках включите все модели из предыдущих выпусков вместе с вашей новейшей моделью (если она изменилась), и пользователи смогут мигрировать каждый раз.

Вот мой код на данный момент,Важная строка:

[fileManager removeItemAtPath:iCloudData error:&error];

Но она используется только во время отладки для удаления вашей старой базы данных.Вот производственный код в AppDelegate.m:

- (NSManagedObjectModel *)managedObjectModel
{
    if (__managedObjectModel != nil)
    {
        return __managedObjectModel;
    }
    //NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
    //__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    //NSArray *testArray = [[NSBundle mainBundle] URLsForResourcesWithExtension:@"momd"subdirectory:nil];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];

    if( !path ) path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"mom"];

    NSURL *modelURL = [NSURL fileURLWithPath:path];

    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    //__managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];

    return __managedObjectModel;
}

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

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

    // Set up iCloud in another thread:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // ** Note: if you adapt this code for your own use, you MUST change this variable:
        NSString *iCloudEnabledAppID = @"RW6RS7HS69.com.zsculpt.soaktest";

        // ** Note: if you adapt this code for your own use, you should change this variable:        
        NSString *dataFileName = @"mydailysoak.sqlite";

        // ** Note: For basic usage you shouldn't need to change anything else

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

        if (iCloud) {

            NSLog(@"iCloud is working");

            NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];

            NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID);
            NSLog(@"dataFileName = %@", dataFileName); 
            NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName);
            NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName);  
            NSLog(@"iCloud = %@", iCloud);
            NSLog(@"iCloudLogsPath = %@", iCloudLogsPath);

            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);

            NSMutableDictionary *options = [NSMutableDictionary dictionary];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
            [options setObject:iCloudEnabledAppID            forKey:NSPersistentStoreUbiquitousContentNameKey];
            [options setObject:iCloudLogsPath                forKey:NSPersistentStoreUbiquitousContentURLKey];

            [psc lock];
        NSError *error;

            [psc addPersistentStoreWithType:NSSQLiteStoreType 
                              configuration:nil 
                                        URL:[NSURL fileURLWithPath:iCloudData] 
                                    options:options 
                                      error:&error];

            if( error )
            {
                NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);

                // comment in this line while debugging if get "Can't find model for source store" error in addPersistentStoreWithType.
                // it means the sqlite database doesn't match the new model and needs to be created from scratch.
                // this happens if you change the xcdatamodel instead of creating a new one under Xcode->Editor->Add Model Version...
                // CoreData can only automatically migrate if there is a new model version (it can't migrate if the model simply changes, because it can't see the difference between the two models).
                // be sure to back up the database if needed, because all data will be lost.
                //[fileManager removeItemAtPath:iCloudData error:&error];

                /*// this is another way to verify the hashes for the database's model to make sure they match one of the entries in the momd directory's VersionInfo.plist
                NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:[NSURL fileURLWithPath:iCloudData] error:&error];

                if( !sourceMetadata )
                    NSLog(@"sourceMetadata is nil");
                else
                    NSLog(@"sourceMetadata is %@", sourceMetadata);*/
            }

            [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];
        NSError *error;

            [psc addPersistentStoreWithType:NSSQLiteStoreType 
                              configuration:nil 
                                        URL:localStore 
                                    options:options 
                                      error:nil];

        if( error )
            NSLog(@"Error adding persistent store %@, %@", error, [error userInfo]);    
            [psc unlock];
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil];
        });
    });

    return __persistentStoreCoordinator;   
}
5 голосов
/ 27 августа 2010

Сообщение об ошибке означает, что он не может найти файл скомпилированной модели .mom для существующего хранилища. Core Data ищет точную версию .mom, которая настроила хранилище. Файл .mom сообщает Core Data, как отобразить сериализованные данные в файле в объекты. Без этого файла модели он не знает, как перенести хранилище в новую модель, потому что он не знает, какие данные поступают с каждым объектом или свойством объекта.

Я видел это только один раз, и IIRC был причиной того, что новый файл .mom имел то же имя и местоположение, что и старый. Когда приложение было обновлено, старый файл .mom был перезаписан.

Попробуйте изменить имя нового файла модели и посмотрите, поможет ли это. Если нет, нам, вероятно, понадобится более подробная информация о том, что вы делаете.

0 голосов
/ 10 апреля 2014

используйте основные миграции данных для обновления старой базы данных новой схемой с потерей ваших данных.

https://developer.apple.com/library/ios/documentation/cocoa/conceptual/CoreDataVersioning/Articles/vmLightweightMigration.html

0 голосов
/ 01 марта 2011

У меня тоже была такая же проблема.Я решил это, удалив мою старую базу данных и снова собрав проект.Я не уверен, что это правильный путь.Очевидно это указывает на неправильный файл базы данных.В моем случае я создавал простой проект с использованием основных данных и пытался выполнить миграцию.Когда я создавал новую модель с дополнительным столбцом и строил свой проект, было 2 файла - coreData.sqlite и coreData ~ .sqlite ... Так что я чувствую, что неверная база данных указывает на и, следовательно, ошибка.Когда я удалил базу данных и снова собрал проект, он отлично сработал для меня.

Если вы удалите базу данных, лучше всего сохранить копию базы данных в другом месте, чтобы не потерять ее.

...