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 или многопоточность очень хорошо, возможно, я делаю очевидную ошибку...
Ответы
Ответ 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 Datastrong > , чтобы выполнить следующие действия:
(1) Reset симулятор.
(2) Удалите базу данных sqlite из своего проекта.
(3) Удалите каталог симулятора с вашего устройства.
Удивительно, но я обнаружил, что выполнение шагов 1 и 2 не всегда работает без шага 3.
Если вы сделаете это, вам потребуется перезагрузить хранилище основных данных.