Обновить NSPersistentStoreCoordinator в AppDelegate из ViewController

У меня есть приложение, в котором PersistentStoreCoordinator настроен в AppDelegate. Я хочу загрузить новую базу данных sqlite из списка сохраненных файлов sqlite. Я счастлив удалить существующий файл Persistent Store и sqlite и заменить файл sqlite файлом, загруженным из таблицы. Однако как перезагрузить / обновить PersistentStoreCoordinator из действия ViewController выбора нового файла? Я попытался установить AppDelegate в качестве делегата ViewController, но это, кажется, создает всевозможные циклические ссылки в приложении. Кроме того, каков точный метод для перезагрузки PersistentStoreCoordinator?

Я пробовал этот код, но он просто очищает постоянное хранилище без обновления загруженным файлом sqlite (Working.sqlite - это имя текущей текущей версии базы данных sqlite):

 -  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
        targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"]; 
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

        NSPersistentStore *store = [[delegate.persistentStoreCoordinator persistentStores] lastObject];
        NSError *error;

        NSPersistentStoreCoordinator *storeCoordinator = delegate.persistentStoreCoordinator;
        [storeCoordinator removePersistentStore:store error:&error];
        [[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];


        NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
        NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
        NSLog(@"selectedPlan is: %@", loadName);


        if (![[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error]) {
            NSLog(@"Error: %@", error);
        }



        else {
            [delegate managedObjectContext];
            [delegate managedObjectModel];
            [delegate persistentStoreCoordinator];
           [self.delegate planWasSelectedOnTheFileTableViewController:self];}

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

-  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"]; AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

    NSPersistentStore *store = [[delegate.persistentStoreCoordinator persistentStores] lastObject];
    NSError *error;

    NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
    NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
    NSLog(@"selectedPlan is: %@", loadName);
    [delegate.persistentStoreCoordinator removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];

    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");

    }
    else {NSLog(@"File deleted");}
    [[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");

    }
    else {NSLog(@"path empty");}
    NSURL *storeURL = [NSURL fileURLWithPath:targetPath];
        error = nil;
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                                 [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    [delegate.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]; {            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }

       [self.delegate planWasSelectedOnTheFileTableViewController:self];}

Маркус - я думаю, что это отражает твой совет, но я все еще получаю сбой приложения на этапе addPersistentStore с журналом "неразрешенной ошибки":

-  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

    //setting path to current working sqlite file
    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"];

    //setting path to selected sqlite file
    NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
    NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
    NSLog(@"selectedPlan is: %@", loadName);

    // retrieve the store URL
    NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
    NSString *storeName = [storeURL absoluteString];
     NSLog(@"Persistent Store is: %@", storeName);
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It was there before it was deleted");}

    // remove the store
    NSError *error;
    [delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:&error];
{NSLog(@"Unresolved error on remove %@, %@", error, [error userInfo]);
    abort();}
error = nil;


    // remove the store file and check it's gone
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");}
        else {NSLog(@"File deleted");}

    // copy in new file and check it's there
    [[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
        if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");}
        else {NSLog(@"path empty");}

    //re-attach the store
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    [delegate.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
    {NSLog(@"Unresolved error on add %@, %@", error, [error userInfo]);
        abort();}
 }

Следуя совету Маркуса, я добавил журнал ошибок в removePersistentStore в измененном коде выше. Проблема возникает в действии удаления. Файл журнала заканчивается следующим образом:

2013-06-01 01: 10: 02.478 inControl [1238: 907] Постоянное хранилище: file: //localhost/var/mobile/Applications/D34C6065-8D59-480F-ABA4-9F10C690F26C/Library/Working.sqlite

2013-06-01 01: 10: 02.481 inControl [1238: 907] Он был там до того, как был удален

2013-06-01 01:10:02.486 inControl[1238:907] Неразрешенная ошибка при удалении (null), (null)

Окончательный рабочий код, следуя советам Маркуса:

-  (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

    //setting path to current working sqlite file
    NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
    targetPath = [libraryPath stringByAppendingPathComponent:@"Working.sqlite"];

    //setting path to selected sqlite file
    NSString *loadPath = [workingDirPath stringByAppendingPathComponent:[directoryContent objectAtIndex:indexPath.row]];
    NSString *loadName = [[directoryContent objectAtIndex:indexPath.row] stringByDeletingPathExtension];
    NSLog(@"selectedPlan is: %@", loadName);

    // retrieve the store URL
    NSURL * storeURL = [NSURL fileURLWithPath:targetPath];
    NSString *storeName = [storeURL absoluteString];
     NSLog(@"Persistent Store is: %@", storeName);
    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It was there before it was deleted");}

    // remove the store
    NSError *error;
    NSPersistentStoreCoordinator *psc = [delegate persistentStoreCoordinator];
    NSPersistentStore *ps = [[psc persistentStores] lastObject];
    if (![psc removePersistentStore:ps error:&error]) {
        NSLog(@"Remove Store Failure: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }    error = nil;

    // remove the store file and check it's gone
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];


    if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"It's still there!");}
        else {NSLog(@"File deleted");}

    // copy in new file and check it's there
    [[NSFileManager defaultManager] copyItemAtPath:loadPath toPath:targetPath error:&error];
        if ([[NSFileManager defaultManager] fileExistsAtPath:targetPath]){NSLog(@"File Copied");}
        else {NSLog(@"path empty");}

    [delegate.managedObjectContext reset];
    //re-attach the store
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        NSLog(@"Add Store Failure: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }
    } 

1 ответ

Решение

Лучший ответ - сделать -removePersistentStore:error: на NSPersistentStoreCoordinator тогда сделай -addPersistentStoreWithType: configuration: configuration URL: options: error:

В рамках этого процесса я бы сделал -reset на NSManagedObjectContext а затем опубликовать NSNotification что ваш контроллер представления слушает, а затем ваш контроллер представления может перезагрузить свои данные.

Вам не нужно удалять любые файлы с диска.

Обновление 1

Во-первых, вы должны сказать нам, что такое авария:)

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

Обновите вопрос с ошибкой, и это поможет разобраться.

Обновление 2

Этот код не имеет никакого смысла:

// remove the store
NSError *error;
[delegate.persistentStoreCoordinator removePersistentStore:[[delegate.persistentStoreCoordinator persistentStores] lastObject] error:&error];
{NSLog(@"Unresolved error on remove %@, %@", error, [error userInfo]);
abort();}
error = nil;

Если это верно, то это неправильно. Так должно быть:

NSError *error;
NSPersistentStoreCoordinator *psc = [delegate persistentStoreCoordinator];
NSPersistentStore *ps = [[psc persistentStores] lastObject];
if (![psc removePersistentStore:ps error:&error]) {
  NSLog(@"Failure: %@\n%@", [error localizedDescription], [error userInfo]);
  abort();
}

Не отвечайте на ошибку, чтобы определить ошибку, проверьте BOOL это возвращается из звонка.

Другие вопросы по тегам