Подтвердить что ты не робот

Reset постоянное хранилище CoreData

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

4b9b3361

Ответ 1

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

От Документация NSManagedObjectContext

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

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

Ответ 2

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

Ответ 3

Все еще не работает! Прерывание, вызванное ссылкой 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

Вот решение. Могут быть несколько более элегантных опций (lock...), но это работает.

/**
 * 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;
}

Ответ 5

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

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];

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

Ответ 6

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

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

Ответ 7

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

(1) Reset симулятор.

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

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

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

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