Легкая миграция NSPersistentDocument

Я пытаюсь выполнить облегченную миграцию хранилища SQLite в Core Data. Работа над Lion 10.7.3 с Xcode 4.3.1.

В моем подклассе NSPersistentDocument (AccountDocument) я переопределил метод, используемый для настройки координатора постоянного хранилища, чтобы он получил правильные параметры для миграции:

- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error
{
    NSMutableDictionary *newStoreOptions;
    if (storeOptions == nil) {
        newStoreOptions = [NSMutableDictionary dictionary];
    }
    else {
        newStoreOptions = [storeOptions mutableCopy];
    }
    [newStoreOptions setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
    [newStoreOptions setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];

    BOOL result = [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:newStoreOptions error:error];
    return result;
}

(Спасибо Малкольму Кроуфорду за этот совет: http://homepage.mac.com/mmalc/CocoaExamples/controllers.html)

Когда я запускаю приложение, оно не работает в реализации -managedObjectModel в NSPersistentDocument:

* thread #1: tid = 0x2703, 0x00007fff931d9350 libobjc.A.dylib`objc_msgSend_vtable13 + 16, stop reason = EXC_BAD_ACCESS (code=13, address=0x0)
    frame #0: 0x00007fff931d9350 libobjc.A.dylib`objc_msgSend_vtable13 + 16
    frame #1: 0x00007fff8935e975 CoreData`-[NSKnownKeysDictionary1 _setValues:retain:] + 197
    frame #2: 0x00007fff8935f288 CoreData`_newReadModelFromBytes + 648
    frame #3: 0x00007fff8935b93e CoreData`+[NSManagedObjectModel(_NSManagedObjectModelPrivateMethods) _newModelFromOptimizedEncoding:error:] + 9310
    frame #4: 0x00007fff89359451 CoreData`-[NSManagedObjectModel(_NSManagedObjectModelPrivateMethods) initWithContentsOfOptimizedURL:] + 305
    frame #5: 0x00007fff89358d7b CoreData`-[NSManagedObjectModel initWithContentsOfURL:] + 443
    frame #6: 0x00007fff893e9519 CoreData`+[NSManagedObjectModel mergedModelFromBundles:] + 377
    frame #7: 0x00007fff8ded7037 AppKit`-[NSPersistentDocument managedObjectModel] + 301
    frame #8: 0x00007fff8ded70b3 AppKit`-[NSPersistentDocument managedObjectContext] + 75
    frame #9: 0x00007fff8ded6e3f AppKit`-[NSPersistentDocument _persistentStoreCoordinator] + 18
    frame #10: 0x00007fff8ded6b5d AppKit`-[NSPersistentDocument configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:] + 51
    frame #11: 0x0000000100003193 BeanCounter`-[AccountDocument configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error:] + 419 at AccountDocument.m:298

Судя по документации, реализация по умолчанию выглядит примерно так:

- (id)managedObjectModel
{
    NSManagedObjectModel *result = [NSManagedObjectModel mergedModelFromBundles:nil];
    return result;
}

Итак, чтобы немного отладить проблему, я переопределил этот метод следующим образом:

- (id)managedObjectModel
{
    NSBundle *bundle = [NSBundle mainBundle];
    NSURL *url = [bundle URLForResource:@"AccountDocument2" withExtension:@"momd"];
    NSManagedObjectModel *result = [[[NSManagedObjectModel alloc] initWithContentsOfURL:url] autorelease];  
    return result;
}

(Спасибо Джеффу Ламарче за идею: http://iphonedevelopment.blogspot.com/2009/09/core-data-migration-problems.html).

И пакет, и URL-адрес указывают на ожидаемые мной места (и я последовал совету Маркуса Зарры по очистке проекта, чтобы в пакете приложения не было случайных пакетов .mom или .momd: Использование mergedModelFromBundles: и управление версиями (CoreData)). Тем не менее, приложение продолжает вылетать при загрузке модели с URL-адреса.

Я проверил, что AccountDocument2.xcdatamodeld - это пакет, который имеет две модели для управления версиями: AccountDocument 2.xcdatamodel и (исходный) AccountDocument.xcdatamodel. Во всплывающем меню «Версия базовой модели данных» в свойствах файла задано значение «AccountDocument 2».

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

Очевидно, я здесь что-то не так делаю, но понятия не имею, что именно. Любая помощь будет очень признательна ...

Обновление:

По предложению Мартина (и проверке документации NSPersistentDocument) я попытался использовать этот код для средства доступа:

- (id)managedObjectModel
{
    static id sharedManagedObjectModel = nil;

    if (sharedManagedObjectModel == nil) {
        NSBundle *bundle = [NSBundle mainBundle];
        NSURL *url = [bundle URLForResource:@"AccountDocument2" withExtension:@"momd"];
        sharedManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
    }

    return sharedManagedObjectModel;
}

По-прежнему происходит сбой…

Обновить

После некоторых предложений в Twitter я обновился до Xcode 4.3.2, но проблемы не исчезли.

ОБНОВЛЕНИЕ ЯРОСТИ

Я только что создал пакет модели с версией (AccountDocument2.xcdatamodeld), используя Xcode 4.2 на Snow Leopard. После сборки и запуска приложения все работает должным образом.

Затем я вернул пакет файлов AccountDocument2.xcdatamodeld обратно в Lion и Xcode 4.3.2. Когда я создаю и запускаю приложение, оно продолжает вылетать при загрузке ресурса .momd. Да, детки, это означает, что виноваты Xcode 4.3.x и компилятор модели данных (MOMC). Я не вижу другого пути, кроме как делать все свои сборки на Snow Leopard.

Я не из тех, кто использует Xcode 4, но когда мы оказываемся в ситуации, когда инструментальная цепочка не может создать непрозрачный файл (.mom и .momd) из непрозрачной спецификации (.xcdatamodel и .xcdatamodeld), это довольно сложно Будьте оптимистичны относительно состояния инструментов Mac и iOS. Смешно, что основной компонент этих платформ ломается до такой степени, что я не могу создавать и запускать свое приложение в последней версии SDK и инструментов разработчика.

Это дошло до этого обновления

Еще одно доказательство того, что это серьезная ошибка компилятора модели данных (MOMC) в Xcode 4.3.2: если я скопирую пакет .momd из папки ресурсов, созданной Xcode 4.2, в свой проект и добавлю их в сборку как файлы копирования этап сборки, приложение работает нормально.

Я также провел несколько тестов, в которых я удалил правила проверки и значения по умолчанию для атрибутов различных сущностей (на основе предложения Маркуса ниже). Без изменений, компилятор по-прежнему создает недопустимый .momd. Я также попытался создать модель с версией, в которой НИЧЕГО не изменилось: скомпилированный .momd продолжал давать сбой. Итак, все, что у вас есть в ваших текущих моделях (и данных, которые они представляют), является источником проблемы.

Также обратите внимание: эта ошибка не изолирована от NSPersistentDocument (как я изначально думал, когда задавал этот вопрос). Я могу вызвать сбой приложения, просто используя [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL].

На данный момент я буду редактировать / управлять версиями своих моделей с помощью Xcode 4.2 на Snow Leopard и перемещать скомпилированные ресурсы в Xcode 4.3.2 на Lion. Если вы каким-либо образом используете Core Data, я предлагаю вам делать то же самое, пока эта ошибка не будет устранена. Поверьте, вы потратите дни, пытаясь понять, что, черт возьми, происходит, если вы этого не сделаете.

Теперь, чтобы отправить радар…

Обновление радара

Я только что отправил этот радар:

http://www.openradar.me/11184500

Обновление "О, черт возьми, должно быть, лев"

Я только что загрузил и установил инструменты Xcode 4.2 для Lion с http://developer.apple.com/downloads. Пример приложения, используемого в радаре, по-прежнему дает сбой.

(Примечание: вы не можете установить Xcode 4.2.1, потому что срок действия сертификата, используемого для подписи DeveloperTools.pkg, истек. Только Xcode 4.2 будет работать.)

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

Надеюсь, у вас есть копия Snow Leopard с Xcode 4.2, сидящая без дела: http://furbo.org/2012/03/28/vmware-for-developers/

Запросы на выборку WTF имеют отношение к версионным объектам и обновлению атрибутов

Через Эвадну Ву в Twitter:

https://twitter.com/#!/evadne/status/187625192342818818

И как она это сделала:

https://twitter.com/#!/evadne/status/187629091518816258

(Файлы .mom представляют собой двоичные списки.)

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


person chockenberry    schedule 03.04.2012    source источник
comment
Вы используете ARC в классе, который определяет configurePersistentStoreCoordinatorForURL:::::? В противном случае вы теряете копию, сделанную вами из storeOptions.   -  person Peter Hosey    schedule 04.04.2012
comment
В зависимости от того, присутствует ли существующий storeOptions, newStoreOptions будет либо сохранен (если вы вызываете [storeOptions mutableCopy]), либо автоматически выпускается, если вы следуете пути, который вызывает [NSMutableDictionary dictionary]   -  person Mike C.    schedule 04.04.2012
comment
Питер прав в том, что есть утечка newStoreOptions, но на самом деле это не имеет значения, так как я только что проверил путь кода, а storeOptions пришел как nil. В любом случае это не источник проблемы при загрузке модели (модели не могут быть загружены, а тем более перенесены).   -  person chockenberry    schedule 04.04.2012
comment
@chockenberry Вы, вероятно, захотите отправить свое последнее обновление или два в качестве ответа, а не как редактирование исходного сообщения.   -  person Sophie Alpert    schedule 04.04.2012
comment
Мы столкнулись с этой или невероятно похожей проблемой, но нашли более простой способ обойти ее, но в равной степени разочаровывающий. Когда облегченная миграция не удалась, мы добавили модель сопоставления, чтобы повозиться. Отлично. Затем мы удалили его, чтобы снова попробовать облегченную миграцию, и, конечно же, она сработала. Пройдя взад и вперед и пробуя это снова и снова (с самого начала), мы могли надежно доказать, что просто добавление модели сопоставления каким-то образом изменило файл модели туда, где сработает облегченная версия. Гррррр.   -  person Stephen Tallent    schedule 04.04.2012
comment
@StephenTallent Спасибо за совет, но, к сожалению, в данном случае он не работает. Все еще застряли…   -  person chockenberry    schedule 04.04.2012
comment
Я думаю, было бы полезно написать реальный ответ с полным объяснением, а не просто ссылаться на эти твиты. Затем отметьте ответ как таковой для будущих людей, которые придут к этому вопросу.   -  person Bryan    schedule 05.04.2012
comment
Продолжай, Крейг, я думаю, в какой-то момент ты найдешь @interface NSManagedObject (NSManagedObjectFetchBugApology) - (void)heyCraig:(id)in1 sorryAboutThat:(id)in2 mustHaveSlippedTheUnitTests:(id)in3 theRootCauseIsBothVerySimpleAndVeryComplicated:(id)in4 thanksForTheDetailedRadarWeOweYouABeerAtNextWWDCSeeYouThere:(id)in5; @end   -  person Pierre Lebeaupin    schedule 05.04.2012


Ответы (4)


Скомпилированные ресурсы .momd могут быть загружены после изменения запроса на выборку "existingPartner" с:

name == $name

to:

name == $NAME

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

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

Используйте возможности CHOCKLOCK, чтобы исправить свои запросы на выборку, или полностью удалите их и положитесь на NSPredicates, созданные в коде.

person chockenberry    schedule 04.04.2012

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

person Martin Pilkington    schedule 03.04.2012
comment
Обновил приведенные выше примеры кода, и, к сожалению, это не помогает. - person chockenberry; 04.04.2012

Основываясь на вашей теории, что это проблема MOMC, есть ли у вас какие-либо правила проверки в маме?

Я видел отчеты, в которых правила проверки не выдерживают испытания MOMC 4.x.

person Marcus S. Zarra    schedule 04.04.2012
comment
Спасибо за подсказку, Маркус. Я попытался удалить правила проверки как из исходной, так и из версионной модели, но при загрузке все равно происходит сбой. - person chockenberry; 04.04.2012

Это может быть отчасти связано с проблемой, с которой я столкнулся с использованием запросов на выборку, когда iOS5 только вышла в бета-версии. Это вызывало предупреждение о сборке и приводило к сбою приложения при запуске. На самом деле я не использовал запрос на выборку, поэтому удалил его, и все работало нормально: Предупреждение основных данных: хэш-информация о версии доступна не для всех моделей

person Z S    schedule 05.04.2012