Облегченная миграция iPhone Core Data Какао ошибка 134130: Не удается найти модель для исходного хранилища

Folks,

Облегченная миграция не выполняется для меня 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 - Для гуглеров, которые спотыкаются на этой странице, вот все соответствующие страницы, которые вы могли бы рассмотреть, ниже. К сожалению, ни один из них не решил мою проблему.

ОБНОВИТЬ

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

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 ответов

Решение

Folks,

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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 и посмотрим, чего не хватает. Возможно, не существует единственной модели, которая содержит все необходимые версии сущностей в существующем постоянном хранилище. Это может произойти из-за (случайных?) Изменений в модели до или после установки новой версии модели?

Ну, в моем случае происходило точно то же самое, и я работал на 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;
}
Другие вопросы по тегам