Облегченная миграция данных iPhone Core Какао ошибка 134130: не удается найти модель для исходного хранилища - PullRequest
16 голосов
/ 30 июня 2010

Народ,

Легкая миграция не выполняется для меня 100% времени в этой строке:

[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]

с ошибкой:

Error: Error Domain=NSCocoaErrorDomain Code=134130 UserInfo=0x4fbff20 "Operation could not be completed. (Cocoa error 134130.)"
"Can't find model for source store";

Вотмой контекст управляемого объекта, модель и постоянное хранилище:

- (NSManagedObjectContext *) managedObjectContext {

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

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }
    return managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel {

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

    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
    return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

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

    NSError *error;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

    // Allow inferred migration from the original version of the application.
    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(@"Error: %@",error);
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return persistentStoreCoordinator;
}

У меня есть две версии моей модели в моем проекте: версия 4 и версия 5. Если я устанавливаю версию 4 по умолчанию, она работаетхорошо.Если я выберу «Дизайн -> Модель данных -> Добавить версию модели» (как описано в этом посте ), внесу изменения, Проект -> Модель данных -> Установить текущую версию, создайте и запустите, он будетошибка с вышеупомянутой ошибкой «Не удается найти модель для источника».Установите модель обратно в версию 4, без проблем, addPersistentStoreWithType.В качестве альтернативы, если я добавлю версию модели и не внесу изменений, просто перейдите с версии 4 на 5 без добавления каких-либо новых полей, никаких проблем.Если я затем попытаюсь перейти с 5 на 6, вышеупомянутая ошибка.

Этот код не работает как на симуляторе, так и на телефоне.Я прочитал несколько рецептов, призывающих к удалению и переустановке приложения, которое работает как для симулятора, так и для телефона, но я боюсь, что когда я выпущу это для реальных пользователей, это сломает мою установленную базу, так как они не смогут удалить и переустановить- App Store автоматически обновит их.

Этот код работал в прошлых выпусках без каких-либо изменений с моей стороны - отсюда моя способность довести его до версии 4. Я недавно обновился до сборки XCode 3.2.3 для iOS4, в которой может быть что-тоделать с этим.

У кого-нибудь еще возникла эта проблема внезапно, как у меня?Кому-нибудь удалось пройти мимо этого?Спасибо.

PS - Для пользователей Google, которые наткнулись на эту страницу, ниже приведены все соответствующие страницы, которые вы могли бы рассмотреть, прочитав их.К сожалению, ни одна из них не решила мою проблему.

ОБНОВЛЕНИЕ

Хотя это ненастоящее исправление, оно избегает сценария сбоя клиента: просто удалите файл базы данных:

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {



    // Delete file
    if ([[NSFileManager defaultManager] fileExistsAtPath:storeUrl.path]) {
        if (![[NSFileManager defaultManager] removeItemAtPath:storeUrl.path error:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) 
    {
        // Handle the error.
        NSLog(@"Error: %@",error);
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();

    }
}    

ОБНОВЛЕНИЕ 2

Вот что происходит, когда я проверяю VersionInfo.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>NSManagedObjectModel_CurrentVersionName</key>
        <string>Profile 5</string>
        <key>NSManagedObjectModel_VersionHashes</key>
        <dict>
                <key>Profile</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        ZIICGgMBreuldkPXgXUhJwKamgwJzESM5FRTOUskomw=
                        </data>
                </dict>
                <key>Profile 2</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        tEB7HrETWOSUuoeDonJKLXzsxixv8ALHOoASQDUIZMA=
                        </data>
                </dict>
                <key>Profile 3</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        qyXOJyKkfQ8hdt9gcdFs7SxKmZ1JYrsXvKbtFQTTna8=
                        </data>
                </dict>
                <key>Profile 4</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        lyWDJJ0kGcs/pUOModd3Q1ymDvdRiNXui4NCpLxDFSw=
                        </data>
                </dict>
                <key>Profile 5</key>
                <dict>
                        <key>Profile</key>
                        <data>
                        V4PyRK1ezj3xK1QFRCTVzGOqyJhEb7FRMzglrTsP0cI=
                        </data>
                </dict>
        </dict>
</dict>
</plist>

Вот код, который я написал для проверки моей модели (обратите внимание, мне пришлось выйти и добавить кодировщик base64, так как это то, чтонаходится в файле VersionInfo.plist)

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {


    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeUrl error:&error];
    NSLog(@"%@",storeMeta);
    id someObj = [[storeMeta objectForKey:@"NSStoreModelVersionHashes"] objectForKey:@"Profile"];
    NSLog(@"%@",someObj);
    NSLog(@"%@",[NSString base64StringFromData:someObj length:[someObj length]]);

А вот отладочный вывод:

{
    NSPersistenceFrameworkVersion = 310;
    NSStoreModelVersionHashes =     {
        Profile = <97258324 9d2419cb 3fa5438c a1d77743 5ca60ef7 5188d5ee 8b8342a4 bc43152c>;
        SerializedMessage = <4530863c d943479a edfb4dfb 5059c28d d6137dc4 d1153d36 ed52be49 11074f13>;
    };
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
    );
    NSStoreType = SQLite;
    NSStoreUUID = "823FD306-696F-4A0F-8311-2792825DC66E";
    "_NSAutoVacuumLevel" = 2;
}

<97258324 9d2419cb 3fa5438c a1d77743 5ca60ef7 5188d5ee 8b8342a4 bc43152c>
lyWDJJ0kGcs/pUOModd3Q1ymDvdRiNXui4NCpLxDFSw=

Как видите, последняя строка, начинающаяся с 'ly', соответствует профилю 4в VersionInfo.plist ... следовательно, я не вижу причин, по которым он должен давать сбой.Есть еще идеи?

Ответы [ 5 ]

9 голосов
/ 23 июня 2011

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

Эта проблема вызвана тем, что Xcode не удаляет старые файлы momc из симулятора / устройства dev при изменении файла модели, например, при изменении имени.Старый файл остается, что вызывает путаницу.Это то, что вы видите только во время разработки, потому что это артефакт того, как XCode манипулирует комплектом приложений, не переустанавливая его каждый раз, как это должно происходить в версии выпуска.

Вы можете подтвердить эту запись возврата:

[[NSBundle mainBundle] URLsForResourcesWithExtension:@"momc"subdirectory:nil];

... которая должна показать вам все файлы скомпилированной модели в комплекте приложений

Это плохая практикаполагаться на миграцию во время разработки, потому что очень часто происходит сбой миграции, если вы вносите изменения в модель и хранилище.Вы должны использовать миграцию только после того, как весь код прибит.Я также рекомендовал бы восстанавливать ваш магазин с нуля каждый раз, когда вы запускаете.Легко накапливать мусор в магазине, меняя модель.

4 голосов
/ 23 июня 2011

У меня была точная проблема с esilver, и я нашел этот вопрос через Google. Тем не менее, исправление, которое работало для меня, больше нигде не было на SO (что я знаю), так что здесь идет:

Если в вашем пакете несколько копий ваших *.mom файлов (скомпилированных объектных моделей), Core Data может запутаться при попытке выполнить миграцию от вашего имени.

Наша проблема заключалась в том, что каждый отдельный файл модели (Data.xcdatamodel, Data_V1.xcdatamodel, Data_V2.xcdatamodel и т. Д.) Находился не только внутри каталога xcdatamodeld/ (который был включен как нечто для компиляции в процессе сборки), но также каждый файл был также включен в список «Источники компиляции».

Это означало, что полученный пакет имел два набора файлов *.mom: один внутри xcdatamodeld/ и один на верхнем уровне. Я думаю, что Core Data очень, очень запуталась и привела к этой ошибке. Удаление каждого файла xcdatamodel из «исходников компиляции» и выход из каталога xcdatamodeld решили эту проблему для нас (например, автоматическое управление версиями и запуск снова). Надеюсь, это поможет!

4 голосов
/ 30 июня 2010

Я прочитал ваш обновленный вопрос.С версиями моделей становится все более беспорядочно.

Вы должны попытаться проверить версию модели, которую фактически запрашивает существующее хранилище, и попытаться перечислить все доступные модели в комплекте приложений во время выполнения.


Я смотрю в каталоге моделей моих приложений

NSString *modelDirectoryPath = [[NSBundle mainBundle] pathForResource:@"MyModel" ofType:@"momd"];

Я не уверен, что разработчики обычно делают это, но я держу версии своих моделей под разными именами ... так что я там:

  • VersionInfo.plist
  • MyModel.mom
  • MyModel2.mom

Хэши версий, перечисленные в VersionInfo.plist, должныпомочь вам устранить неполадки.Найдите хеш версии, требуемый существующим постоянным хранилищем, и посмотрите, можете ли вы найти его в хешах версии, перечисленных в VersionInfo.plist.

На самом деле, я не вижу способа написать какое-либокод, который спросит постоянное хранилище, каковы его хеш-версии.NSPersistentStoreCoordinator или NSMigrationManger, кажется, делают это в частном порядке.то есть они проверяют версии сущностей постоянного хранилища по модели, с которой загружено хранилище.


Был еще один быстрый просмотр, и он доступен в метаданных хранилища.Легко и просто!

NSError *error;
NSURL *storeURL = [NSURL fileURLWithPath:[[self class] storePath]];
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeURL error:&error];

И, глядя в storeMeta, я получаю ключ с

<CFString 0x7328050 [0x2724380]>{contents = "NSStoreModelVersionHashes"} = <CFBasicHash 0x7328340 [0x2724380]>{type = immutable dict, count = 5,
entries =>
    0 : <CFString 0x7328110 [0x2724380]>{contents = "MyEntityNameOne"} = <CFData 0x73281b0 [0x2724380]>{length = 32, capacity = 32, bytes = 0x143325cf121239ce156af2e2a1aad7d9 ... 976977fdf29fc013}
    1 : <CFString 0x7328130 [0x2724380]>{contents = "MyEntityNameTwo"} = <CFData 0x7328200 [0x2724380]>{length = 32, capacity = 32, bytes = 0x0ca6ecf1283d12bd3ca82af39b6b9f5d ... 149dd39a591e0c4d}
    ...    }

Должно быть легко перебрать этот NSStoreModelVersionHashes словарь и записать версию, которая хэширует вашДля магазина требуется.

Вручную сопоставьте его с теми, которые доступны в VersionInfo.plist, и посмотрите, чего не хватает.Возможно, не существует единственной модели, которая содержит все требуемые версии сущностей в существующем постоянном хранилище.Это может произойти из-за (случайного?) Изменения модели до или после установки новой версии модели?

0 голосов
/ 30 июля 2014

Ну, в моем случае происходило точно то же самое, и я работал на iOS 7, и эта проблема поразила мою голову, по крайней мере, неделю, а затем, наконец, найти решение, которое работает для меня , Чтобы заставить его работать, вы должны добавить дополнительное значение в опциях, которое используется для добавления PersistentStore, а затем вы идете (я не уверен насчет другой версии iOS, но да, она определенно будет работать на 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;
}
0 голосов
/ 08 мая 2011

Народ,

Для записи я полностью прекратил использование основных данных.Мой код был сложным и, согласно вышеприведенным проблемам, ненадежным.Я использую SQLLite прямо сейчас и гораздо лучше.Я не могу рекомендовать использовать базовые данные в любом сценарии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...