Использование NSMigrationManager для добавления данных в основное хранилище постоянных данных

StackOverflow https://stackoverflow.com/questions/1630059

Вопрос

Я хотел бы добавить содержимое из одного файла sqlite (который был создан с использованием Core Data с моделью A) в другое хранилище sqlite, которое используется моим приложением (которое использует ту же модель A). Идея состоит в том, чтобы быстро импортировать большие объемы данных.

Проблема, с которой я сталкиваюсь, заключается в том, что приведенный ниже код работает только один раз. Когда я пытаюсь запустить один и тот же код дважды, приложение вылетает в строке, отмеченной моим комментарием. Любая помощь будет принята с благодарностью.

NSError **err;
NSURL *importURL = [NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath]  stringByAppendingPathComponent: @"import.sqlite"]];
NSURL *storeURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"applicationdata.sqlite"]];
NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:[self managedObjectModel] destinationModel:[self managedObjectModel]];
NSMappingModel *mappingModel = [NSMappingModel inferredMappingModelForSourceModel:[self managedObjectModel] destinationModel:[self managedObjectModel] error:err];
NSError **err2;

// the following line crashes when the whole block is ran twice
[migrator migrateStoreFromURL:importURL 
                         type:NSSQLiteStoreType 
                      options:nil 
             withMappingModel:mappingModel 
             toDestinationURL:storeURL 
              destinationType:NSSQLiteStoreType 
           destinationOptions:nil 
                        error:err2];

NSLog(@"import finished");
[migrator release];
Это было полезно?

Решение

Я сразу вижу одну ошибку в этом коде, которая связана с аргументом ошибки этого вызова метода. NSError ** означает, что вы хотите дать методу адрес NSError * , который он будет использовать для записи ссылки на объект ошибки (если ошибка происходит). Прямо сейчас вы просто передаете неинициализированный указатель, который может указывать на что-то допустимое или указывать на общий мусор, в зависимости от того, что в данный момент находится в стеке. Метод migrator запишет на этот счет, иногда без видимого вредного эффекта, но иногда приводит к сбою, как вы видите. Код для этого будет выглядеть так:

NSError *err2 = nil; //you want to initialize to nil, in case method doesn't modify your pointer at all (i.e. no error occurs)

//the method also returns a BOOL indicating success/failure
if (![migrator migrateStoreFromURL:importURL 
                     type:NSSQLiteStoreType 
                  options:nil 
         withMappingModel:mappingModel 
         toDestinationURL:storeURL 
          destinationType:NSSQLiteStoreType 
       destinationOptions:nil 
                    error:&err2])
{
    //handle the error
}

Другие советы

Спасибо Брайану за указание на это.

В итоге я просто добавил дополнительный файл sqlite в постоянные хранилища стека, работает очень хорошо и позволяет нам позже ограничить fetchRequest отдельными хранилищами:

NSError *error = nil;
NSURL *url = SOME_FILEPATH_URL;
NSPersistentStore *newStore = [persistentStoreCoordinator 
                                    addPersistentStoreWithType:NSSQLiteStoreType
                                                 configuration:nil
                                                           URL:url 
                                                       options:opt
                                                         error:&error];

И мы храним словарь всех persistentStores для дальнейшего использования.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top