Iphone 重置CoreData持久存储

Iphone 重置CoreData持久存储,iphone,multithreading,core-data,Iphone,Multithreading,Core Data,基本上,我要做的是清除CoreData持久存储中的所有数据,然后导入新数据。你会怎么做?似乎最简单的解决方案是调用[NSPersistentStoreCoordinator removePersistentStore:error://然后删除该文件。这是最佳实践吗?它是线程安全的吗 多谢各位 # 问题0.1:was 我正在尝试更新CoreData持久存储中的数据。我的用户看到一个包含统计数据的表视图。我想通过删除所有现有数据,然后导入新数据来更新应用程序。我想显示一个进度视图,告诉用户应用程序没

基本上,我要做的是清除CoreData持久存储中的所有数据,然后导入新数据。你会怎么做?似乎最简单的解决方案是调用
[NSPersistentStoreCoordinator removePersistentStore:error://然后删除该文件。这是最佳实践吗?它是线程安全的吗

多谢各位

# 问题0.1:was

我正在尝试更新CoreData持久存储中的数据。我的用户看到一个包含统计数据的表视图。我想通过删除所有现有数据,然后导入新数据来更新应用程序。我想显示一个进度视图,告诉用户应用程序没有挂起

我在AppDelegate中添加了以下
resetPersistentStore
方法(
persistentStoreCoordinator
供参考):

然后在我看来,我是这样做的(在另一个线程中,因为我正在使用
MBProgressHUD

PatrimoineAppDelegate *appDelegate = (PatrimoineAppDelegate *)[[UIApplication sharedApplication] delegate]; 
// Delete everything
[appDelegate resetPersistentStore];
我得到了一个
EXC\u BAD\u access


我不太了解CoreData或多线程,可能我犯了一个明显的错误…

如果您的目标是清空数据存储并用新信息重新加载它,那么最好使用NSManagedObjectContext的
重置
,然后加载新数据

上下文总是有一个“父”持久性存储协调器,提供模型并向包含数据的各种持久性存储发送请求。如果没有协调器,上下文将无法完全正常工作。上下文的协调器提供托管对象模型并处理持久性。从外部存储获取的所有对象都在上下文中注册以及一个全局标识符(NSManagedObjectID的实例),用于唯一标识外部存储的每个对象


删除持久性存储并使用与该存储关联的托管对象上下文可能是导致错误的原因。

以下是解决方案。可能有一些更优雅的选项(锁定…),但这个选项有效

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

仍然不工作!由于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;
}

我发现,只要您可以重新加载核心数据,解决这类问题的最简单方法就是遵循以下步骤:

(1) 重置模拟器

(2) 从项目中删除sqlite数据库

(3) 从计算机中删除模拟器目录

令人惊讶的是,我发现没有步骤3,执行步骤1和2并不总是有效的

如果执行此操作,您将需要重新加载核心数据存储。

您可以交换(或删除)一个持久存储,然后重置上下文(只需确保重新蚀刻内存中的任何对象):


我正在使用它执行导入到专用队列上的临时存储中,然后在完成时覆盖主线程存储并重新加载所有内容。我正在导入到子上下文中,但在我的情况下,删除现有对象而不产生副作用变得很麻烦。

在重置persistentStore之前,必须首先重置所有与之关联的managedObjectContext,否则所有managedObjects将无法访问上下文,这可能会导致错误

最好总是直接从文件系统中删除sqlite文件,并将managedObjectContextpersistentStoreCoordinator设置为nil,而不是调用removePersistentStore。
这将在您下次尝试访问或开始存储时重新创建persistantStore和managedObjectContext。

对于那些在iOS9+上尝试此操作的人,现在有了
destroyPersistentStoreAtURL
replacePersistentStoreAtURL

API。它们非常丑陋且过于复杂。为什么不重建enti重新核心数据堆栈并将新的上下文交给视图控制器?在
NSManagedObjectContext
下交换PSC可能非常危险。其次,您不应该从多个线程中点击
NSManagedObjectContext
,堆栈的设计使您可以出于某种原因为每个线程创建一个上下文;上下文Andres锁定正确。你最好重建整个堆栈,或者从你的存储中删除对象,然后重新加载,而不是删除文件。谢谢你,Marcus,我不确定你是否听到了;你会如何清除数据库中的所有数据,广义上讲?CoreData堆栈意味着什么?假设有alr在持久性存储中已经有一些数据,我想删除所有数据,然后导入新数据。如果我了解苹果的文档,重置MOC不会改变持久性存储中的任何内容,对吗?请确保理解:我的数据已经保存在持久性存储中。简单的
[MOC reset]
(然后保存)还会擦除sqlite文件中的所有内容吗?这解决了一个困扰我一天的问题!谢谢!问题:如何更新外部进程编辑的tableview中的数据:调用[myManagedObjectContext reset];在从fetchedResultsController调用新数据之前。我有很多快乐!charlax,他没有明确地说在保存后重置确实会重置。@Giao删除persistentstore公平吗?还是这是一种不好的做法?请建议我。值得一提的是,重置上下文不会更改存储。它只是删除加载到上下文中的任何内容。我也非常想知道如何执行此操作。这对于预写锁定(WAL)是一个坏主意。磁盘上也会有WAL和shm文件。这在我的情况下起到了作用。之前,我手动重新创建持久存储,这引发了一个错误:对象的持久化
- (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;
}
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];