Сбросить постоянное хранилище CoreData - PullRequest
16 голосов
/ 17 февраля 2010

По сути, я пытаюсь стереть все данные в моем постоянном хранилище CoreData, а затем импортировать новые данные. Как бы вы это сделали? Кажется, что самое простое решение - вызвать [NSPersistentStoreCoordinator removePersistentStore:error:], а затем удалить файл. Это лучшая практика? Это потокобезопасно?

Большое спасибо,

#

Вопрос 0.1: был

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

Я добавил следующий метод resetPersistentStore в мой AppDelegate (persistentStoreCoordinator дан для справки):

// ...
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
// ...

/**
 Returns the persistent store coordinator for the application.
 If the coordinator doesn't already exist, it is created and the application's store added to it.
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: kPersistentStoreFilename]];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return persistentStoreCoordinator;
}

/**
 * Will remove the persistent store
 */
- (NSPersistentStoreCoordinator *)resetPersistentStore {
    NSError *error;

    [managedObjectContext lock];

    // FIXME: dirty. If there are many stores...
    NSPersistentStore *store = [[persistentStoreCoordinator persistentStores] objectAtIndex:0];

    if (![persistentStoreCoordinator removePersistentStore:store error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }  

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

    // Delete the reference to non-existing store
    [persistentStoreCoordinator release];
    persistentStoreCoordinator = nil;

    NSPersistentStoreCoordinator *r = [self persistentStoreCoordinator];
    [managedObjectContext unlock];

    return r;
}

Тогда, на мой взгляд, я делаю (в другой теме, так как я использую MBProgressHUD:

PatrimoineAppDelegate *appDelegate = (PatrimoineAppDelegate *)[[UIApplication sharedApplication] delegate]; 
// Delete everything
[appDelegate resetPersistentStore];

И я получаю EXC_BAD_ACESS ...

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

Ответы [ 7 ]

10 голосов
/ 21 сентября 2015

Для тех, кто пытается это сделать на iOS9 +, теперь есть API destroyPersistentStoreAtURL и replacePersistentStoreAtURL.

8 голосов
/ 17 февраля 2010

Если ваша цель состоит в том, чтобы очистить хранилище данных и перезагрузить его с новой информацией, вам лучше использовать NSManagedObjectContext's reset и затем загружать новые данные.

Из документации NSManagedObjectContext

У контекста всегда есть «родительский» координатор постоянного хранилища, который предоставляет модель и отправляет запросы в различные постоянные хранилища, содержащие данные. Без координатора контекст не является полностью функциональным. Координатор контекста обеспечивает управляемую объектную модель и управляет постоянством. Все объекты, извлеченные из внешнего хранилища, регистрируются в контексте вместе с глобальным идентификатором (экземпляром NSManagedObjectID), который используется для уникальной идентификации каждого объекта во внешнем хранилище.

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

5 голосов
/ 14 декабря 2010

Все еще не работает! Прерывание вызвано ссылкой ManagedObjectContext с неверным хранилищем персистентности. Наконец, это работает, если я удаляю ManagedObjectContext и позволяю приложению воссоздать позже

Вот моя модификация

- (NSPersistentStoreCoordinator *)resetPersistentStore 
{
  NSError *error = nil;

  if ([persistentStoreCoordinator_ persistentStores] == nil)
    return [self persistentStoreCoordinator];

  [managedObjectContext_ release];
  managedObjectContext_ = nil;

  // FIXME: dirty. If there are many stores...
  NSPersistentStore *store = [[persistentStoreCoordinator_ persistentStores] lastObject];

  if (![persistentStoreCoordinator_ removePersistentStore:store error:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
  }  

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

  // Delete the reference to non-existing store
  [persistentStoreCoordinator_ release];
  persistentStoreCoordinator_ = nil;

  NSPersistentStoreCoordinator *r = [self persistentStoreCoordinator];

  return r;
}
4 голосов
/ 17 февраля 2010

Вот решение. Могут быть и более элегантные варианты (блокировка ...), но этот работает.

/**
 * Will remove the persistent store
 */
- (NSPersistentStoreCoordinator *)resetPersistentStore {
    NSError *error = nil;

    if ([persistentStoreCoordinator persistentStores] == nil)
        return [self persistentStoreCoordinator];

    [managedObjectContext reset];
    [managedObjectContext lock];

    // FIXME: dirty. If there are many stores...
    NSPersistentStore *store = [[persistentStoreCoordinator persistentStores] lastObject];

    if (![persistentStoreCoordinator removePersistentStore:store error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }  

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

    // Delete the reference to non-existing store
    [persistentStoreCoordinator release];
    persistentStoreCoordinator = nil;

    NSPersistentStoreCoordinator *r = [self persistentStoreCoordinator];
    [managedObjectContext unlock];

    return r;
}
0 голосов
/ 27 февраля 2015

Перед сбросом persistentStore вы должны сначала сбросить все связанные с этим значения управляемогоObjectContext , иначе все управляемые объекты не будут иметь доступ к контексту, это может вызвать ошибку.

хорошо всегда удалять файл sqlite непосредственно из файловой системы и устанавливать managedObjectContext и persistentStoreCoordinator в nil , вместо вызова removePersistentStore.Это будет воссоздавать persistantStore и managedObjectContext в следующий раз, когда вы попытаетесь получить доступ или начать сохранение.

0 голосов
/ 01 августа 2013

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

for (NSPersistentStore *store in persistentStoreCoordinator.persistentStores) {
    removed = [persistentStoreCoordinator removePersistentStore:store error:nil];
}

// You could delete the store here instead of replacing it if you want to start from scratch
[[NSFileManager defaultManager] replaceItemAtURL:storeURL
                                   withItemAtURL:newStoreURL
                                  backupItemName:nil
                                         options:0
                                resultingItemURL:nil
                                           error:nil];

NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];

[myContext reset];

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

0 голосов
/ 06 ноября 2012

Я нашел самый простой способ справиться с этими типами проблем, , если вы можете перезагрузить ваши базовые данные , это выполнить следующие шаги:

(1) Сброс симулятора.

(2) Удалите базу данных sqlite из вашего проекта.

(3) Удалите каталог симулятора со своего компьютера.

Удивительно, но я обнаружил, что выполнение шагов 1 и 2 не всегда работает без шага 3.

Вам потребуется перезагрузить хранилище базовых данных, если вы сделаете это.

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