【问题标题】:Delete/Reset all entries in Core Data?删除/重置 Core Data 中的所有条目?
【发布时间】:2010-11-07 20:20:39
【问题描述】:

您知道有什么方法可以删除存储在 Core Data 中的所有条目吗?我的架构应该保持不变;我只想将其重置为空白。


编辑

我希望以编程方式执行此操作,以便用户基本上可以点击reset 按钮。

【问题讨论】:

标签: ios cocoa cocoa-touch core-data nsmanagedobject


【解决方案1】:

您仍然可以使用 NSFileManager:removeItemAtPath:: 方法以编程方式删除文件。

NSPersistentStore *store = ...;
NSError *error;
NSURL *storeURL = store.URL;
NSPersistentStoreCoordinator *storeCoordinator = ...;
[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];

然后,只需添加回持久存储以确保正确重新创建它。

遍历每个实体的编程方式既慢又容易出错。这样做的用途是如果您想删除一些实体而不是其他实体。但是,您仍然需要确保保持参照完整性,否则您将无法保留更改。

只需删除商店并重新创建它既快速又安全,当然可以在运行时以编程方式完成。

iOS5+ 更新

随着 iOS 5 和 OS X 10.7 中引入外部二进制存储(allowsExternalBinaryDataStorage 或 Store in External Record File),仅删除 storeURLs 指向的文件是不够的。您将留下外部记录文件。由于这些外部记录文件的命名方案是不公开的,所以我还没有一个通用的解决方案。 – 2012 年 5 月 8 日 23:00

【讨论】:

  • 这可能是可靠性的最佳解决方案。如果我想删除一些但不是全部数据,我会使用这个:stackoverflow.com/questions/1077810/…
  • 我知道如何正确检索 storeCoordinator。但是我不知道如何获得persistentStore。所以你能不能举一个合适的例子,而不是仅仅: NSPersistentStore * store = ...;
  • [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error] 更好。
  • @Pascal 如果您可以获取存储协调器,那么您可以通过 persistentStores 属性访问其所有持久存储。
  • 示例代码,包括如何在此处重新创建一个新的空商店:stackoverflow.com/a/8467628
【解决方案2】:

您可以删除 SQLite 文件 - 但我选择通过使用函数单独清除表来执行此操作:

- (void) deleteAllObjects: (NSString *) entityDescription  {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:_managedObjectContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];


    for (NSManagedObject *managedObject in items) {
        [_managedObjectContext deleteObject:managedObject];
        DLog(@"%@ object deleted",entityDescription);
    }
    if (![_managedObjectContext save:&error]) {
        DLog(@"Error deleting %@ - error:%@",entityDescription,error);
    }

}

我选择逐表执行的原因是,它让我在编写程序时确认删除表的内容是明智的,并且没有我宁愿保留的数据。

这样做会比只删除文件要慢得多,如果我这个方法花费的时间太长,我将更改为文件删除。

【讨论】:

  • 很好的解决方案。谢谢。什么是 DLog()?
  • 啊,是的 - 抱歉,这是我使用的一个特殊功能,仅当构建为 DEBUG 构建时才会执行 NSLog - 只需替换为 NSLog。
  • 您可以在此处查看 DLog 的实现:cimgf.com/2009/01/24/dropping-nslog-in-release-builds
  • 这对我很有效。但是为了让它更快,有没有办法用一个命令删除某个实体的所有对象?就像在 SQL 中一样,您可以执行类似 DROP TABLE entity_name 的操作。我不想删除整个 SQL 文件,因为我只想删除特定实体的所有对象,而不是其他实体。
  • 使用 NSDictionary *allEntities = _managedObjectModel.entitiesByName;获取模型中的所有实体,然后您可以遍历此 NSDictionary 中的键以清除存储中的所有实体。
【解决方案3】:

iOS 10+ 的更新解决方案

使用NSBatchDeleteRequest 删除实体中的所有对象,而无需将它们加载到内存中或遍历它们。

// create the delete request for the specified entity
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = MyEntity.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

// get reference to the persistent container
let persistentContainer = (UIApplication.shared.delegate as! AppDelegate).persistentContainer

// perform the delete
do {
    try persistentContainer.viewContext.execute(deleteRequest)
} catch let error as NSError {
    print(error)
}

此代码已针对 iOS 10 和 Swift 3 进行了更新。如果您需要支持 iOS 9,请参阅this question

来源:

【讨论】:

【解决方案4】:

我编写了一个 clearStores 方法,它遍历每个存储并将其从协调器和文件系统中删除(撇开错误处理):

NSArray *stores = [persistentStoreCoordinator persistentStores];

for(NSPersistentStore *store in stores) {
    [persistentStoreCoordinator removePersistentStore:store error:nil];
    [[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:nil];
}

[persistentStoreCoordinator release], persistentStoreCoordinator = nil;

此方法位于coreDataHelper 类中,该类负责(除其他外)在它为 nil 时创建 persistentStore。

【讨论】:

  • "没有已知的选择器'persistentStores'的类方法"
【解决方案5】:

我从 HomeViewController 类中按钮事件的核心数据中删除所有数据: 这篇文章对我帮助很大,我想我会做出贡献的。

-(IBAction)buttonReset:(id)sender
{
    NSLog(@"buttonReset Pressed");

    //Erase the persistent store from coordinator and also file manager.
    NSPersistentStore *store = [self.persistentStoreCoordinator.persistentStores lastObject];
    NSError *error = nil;
    NSURL *storeURL = store.URL;
    [self.persistentStoreCoordinator removePersistentStore:store error:&error];
    [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];


    NSLog(@"Data Reset");

    //Make new persistent store for future saves   (Taken From Above Answer)
    if (![self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // do something with the error
    }

}

请注意,为了调用 self.persistentStoreCoordinator,我在 Home View Controller 中声明了一个属性。 (不用担心我用于保存和加载的 managedObjectContext。)

@property (nonatomic, retain) NSManagedObjectContext        *   managedObjectContext;
@property (nonatomic, retain) NSPersistentStoreCoordinator  *   persistentStoreCoordinator;

然后在 AppDelegate ApplicationDidFinishLaunching 下面创建一个 HomeViewController 我有:

homeViewController = [[HomeViewController alloc] initWithNibName:@"HomeViewController" bundle:nil];
homeViewController.managedObjectContext = self.managedObjectContext;
homeViewController.persistentStoreCoordinator = self.persistentStoreCoordinator;

【讨论】:

  • @ayteat,这对你有用吗?对我来说它不起作用,请看看这个stackoverflow.com/questions/14646595/…
  • 这是答案,除了使用“AppDelegate *ad = [[UIApplication sharedApplication] delegate];”并将 self 替换为广告。并且不要复制最后两位代码
  • 为什么不在managedObjectContext 上调用reset?如果您对 managedObject 有一些强引用怎么办?
  • @ParagBafna 你是对的,上面的代码示例假设没有对托管对象的强引用。如果您有一些,您应该查看在 managedObjectContext 上调用“reset”并取消引用您拥有的任何托管对象。
  • 嘿,谢谢。另外,有没有办法在应用升级时做到这一点?准确地说,我的要求是当我滚动我们的下一个版本的应用程序时,当用户从 appStore 更新他们的应用程序时,应该删除核心数据 n sqlite 文件并重新初始化为空白。我想出了使用 NSUserDefaults 中的 Bool 值检测应用程序首次启动事件并在应用程序委托的 didfinishLaunchingWithOptions 中检查该值的方法,但不明白如何清除所有这些东西。由于没有按钮,并且应用程序委托没有检测到我的“persistentStore”来清除它,就像您在上面所做的那样。有什么帮助吗?
【解决方案6】:

iOS9+、斯威夫特 2

删除所有实体中的所有对象

func clearCoreDataStore() {
    let entities = managedObjectModel.entities
    for entity in entities {
        let fetchRequest = NSFetchRequest(entityName: entity.name!)
        let deleteReqest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
        do {
            try context.executeRequest(deleteReqest)
        } catch {
            print(error)
        }
    }
}

【讨论】:

【解决方案7】:

MagicalRecord 让这一切变得非常简单。

[MyCoreDataObject MR_truncateAll];

【讨论】:

  • 这很酷,但由于我指定了 CoreData 解决方案,所以离题了
  • Active Record Fetching核心数据解决方案。
  • 但是这样的答案超出了问题的范围。没有理由假设他想使用 addt'l 框架来做到这一点。
  • 我认为这并不能回答问题。这是从一个实体而不是所有实体中删除条目的好方法......!如何枚举模型中的所有实体并在它们上发送MR_truncateAll
  • 查看 MR_truncateAll 的源代码——它获取所有对象但不获取它们的属性(因为我们打算丢弃 NSMO),然后迭代指定实体的对象并删除它们。 github.com/magicalpanda/MagicalRecord/blob/master/MagicalRecord/…
【解决方案8】:

[对要求更新响应的赏金的延迟回答]

查看之前的答案,

  • 按照@Grouchal 和其他人的建议,获取和删除所有项目仍然是一种有效且有用的解决方案。如果您有非常大的数据存储,那么它可能会很慢,但它仍然可以很好地工作。
  • 正如您和@groundhog 所指出的,仅删除数据存储不再有效。它已经过时了即使您不使用外部二进制存储,因为 iOS 7 使用 WAL 模式进行 SQLite 日志记录。在 WAL 模式下,任何 Core Data 持久存储都可能存在(可能很大)日志文件。

但是有一种不同的、类似的方法可以删除有效的持久性存储。关键是将您的持久存储文件放在它自己的不包含任何其他内容的子目录中。不要只是将它粘贴在文档目录(或任何地方)中,而是为持久存储创建一个新的子目录。该目录的内容最终将成为持久存储文件、日志文件和外部二进制文件。如果您想核对整个数据存储,请删除该目录,它们都会消失。

在设置持久存储时,您会这样做:

NSURL *storeDirectoryURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"persistent-store"];
if ([[NSFileManager defaultManager] createDirectoryAtURL:storeDirectoryURL
        withIntermediateDirectories:NO
        attributes:nil
        error:nil]) {
    NSURL *storeURL = [storeDirectoryURL URLByAppendingPathComponent:@"MyApp.sqlite"];
    // continue with storeURL as usual...
}

那么当你想删除商店时,

[[NSFileManager defaultManager] removeItemAtURL:storeDirectoryURL error:nil];

这会递归地删除自定义子目录和其中的所有核心数据文件。

这仅适用于您尚未将永久存储与其他重要数据放在同一文件夹中的情况。就像文档目录一样,里面可能还有其他有用的东西。如果这是您的情况,您可以通过查找您确实想要保留的文件并删除其他所有文件来获得相同的效果。比如:

NSString *docsDirectoryPath = [[self applicationDocumentsDirectory] path];
NSArray *docsDirectoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsDirectoryPath error:nil];
for (NSString *docsDirectoryItem in docsDirectoryContents) {
    // Look at docsDirectoryItem. If it's something you want to keep, do nothing.
    // If it's something you don't recognize, remove it.
}

这种方法可能容易出错。您必须绝对确定您知道要保留的每个文件,否则您可能会删除重要数据。另一方面,您可以在不知道用于存储它们的文件/目录名称的情况下删除外部二进制文件。

【讨论】:

  • 如果你害怕 wal 文件,就禁用它
【解决方案9】:

这里是清除核心数据的组合解决方案。

- (void)deleteAllObjectsInCoreData
{
    NSArray *allEntities = self.managedObjectModel.entities;
    for (NSEntityDescription *entityDescription in allEntities)
    {
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setEntity:entityDescription];

        fetchRequest.includesPropertyValues = NO;
        fetchRequest.includesSubentities = NO;

        NSError *error;
        NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

        if (error) {
                NSLog(@"Error requesting items from Core Data: %@", [error localizedDescription]);
            }

        for (NSManagedObject *managedObject in items) {
            [self.managedObjectContext deleteObject:managedObject];
        }

        if (![self.managedObjectContext save:&error]) {
            NSLog(@"Error deleting %@ - error:%@", entityDescription, [error localizedDescription]);
        }
    }  
}

【讨论】:

    【解决方案10】:

    如果你想删除所有对象,又不想删除备份文件,你可以使用以下方法:

    - (void)deleteAllObjectsInContext:(NSManagedObjectContext *)context
                           usingModel:(NSManagedObjectModel *)model
    {
        NSArray *entities = model.entities;
        for (NSEntityDescription *entityDescription in entities) {
            [self deleteAllObjectsWithEntityName:entityDescription.name
                                       inContext:context];
        }
    }
    
    - (void)deleteAllObjectsWithEntityName:(NSString *)entityName
                                 inContext:(NSManagedObjectContext *)context
    {
        NSFetchRequest *fetchRequest =
            [NSFetchRequest fetchRequestWithEntityName:entityName];
        fetchRequest.includesPropertyValues = NO;
        fetchRequest.includesSubentities = NO;
    
        NSError *error;
        NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
    
        for (NSManagedObject *managedObject in items) {
            [context deleteObject:managedObject];
            NSLog(@"Deleted %@", entityName);
        }
    }
    

    请注意,它可能会非常慢(取决于您的对象图中的对象数量)。

    【讨论】:

    • 应用更新时如何删除旧数据(比如三个表,我要从一个表中清除数据)
    【解决方案11】:

    如果你想去删除所有对象的路线(这比拆除核心数据堆栈简单得多,但性能较差),这是一个更好的实现:

    - (void)deleteAllManagedObjectsInModel:(NSManagedObjectModel *)managedObjectModel context:(NSManagedObjectContext *)managedObjectContext
    {
        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            [managedObjectContext performBlockAndWait:^{
                for (NSEntityDescription *entity in managedObjectModel) {
                    NSFetchRequest *fetchRequest = [NSFetchRequest new];
                    [fetchRequest setEntity:entity];
                    [fetchRequest setIncludesSubentities:NO];
                    NSArray *objects = [managedObjectContext executeFetchRequest:fetchRequest error:nil];
                    for (NSManagedObject *managedObject in objects) {
                        [managedObjectContext deleteObject:managedObject];
                    }            
                }
    
                [managedObjectContext save:nil];
            }];
        }];
        [operation setCompletionBlock:^{
            // Do stuff once the truncation is complete
        }];
        [operation start];
    }
    

    此实现利用NSOperation 执行删除主线程并在完成时通知。您可能希望在完成块中发出通知或其他内容以将状态冒泡回主线程。

    【讨论】:

    • 请注意,您的 NSManagedObjectContext 必须像 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 一样初始化才能使用此方法,否则会出现错误:Can only use -performBlock: on an NSManagedObjectContext that was created with a queue.
    【解决方案12】:

    iOS 10 + Swift 3 解决方案:

    func clearCoreDataStore() {
        let delegate = UIApplication.shared.delegate as! AppDelegate
        let context = delegate.persistentContainer.viewContext
    
        for i in 0...delegate.persistentContainer.managedObjectModel.entities.count-1 {
            let entity = delegate.persistentContainer.managedObjectModel.entities[i]
    
            do {
                let query = NSFetchRequest<NSFetchRequestResult>(entityName: entity.name!)
                let deleterequest = NSBatchDeleteRequest(fetchRequest: query)
                try context.execute(deleterequest)
                try context.save()
    
            } catch let error as NSError {
                print("Error: \(error.localizedDescription)")
                abort()
            }
        }
    }
    

    遍历所有核心数据实体并清除它们

    【讨论】:

      【解决方案13】:

      感谢您的帖子。我跟着它,它对我有用。但我还有一个问题,在任何回复中都没有提到。所以我不确定是不是只有我一个人。

      无论如何,我想我会在这里发布问题以及解决问题的方法。

      我在数据库中有几条记录,我想在将新数据写入数据库之前清除所有内容,所以我做了所有事情,包括

      [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error]; 
      

      然后使用managedObjectContext 访问数据库(现在应该是空的),不知何故数据仍然存在。 经过一段时间的故障排除,我发现我需要重置managedObjectContextmanagedObjectmanagedObjectModelpersistentStoreCoordinator,在我使用managedObjectContext 访问数据库之前。现在我有一个干净的数据库可以写入。

      【讨论】:

      • 那么重置 managedObjectContext、managedObject、managedObjectModel 和 persistentStoreCoordinator 会将包含数据库的文件在删除后恢复?
      【解决方案14】:

      这是一个稍微简化的版本,对 AppDelegate self 的调用更少,最后一点代码被排除在评分最高的答案之外。此外,我收到一个错误“无法从此 NSManagedObjectContext 的协调器访问对象的持久存储”,因此只需将其添加回来。

      NSPersistentStoreCoordinator *storeCoordinator = [self persistentStoreCoordinator];
      NSPersistentStore *store = [[storeCoordinator persistentStores] lastObject];
      NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"dataModel"];
      NSError *error;
      
      [storeCoordinator removePersistentStore:store error:&error];
      [[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];
      
      [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];
      
      if (storeCoordinator != nil) {
          _managedObjectContext = [[NSManagedObjectContext alloc] init];
          [_managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
      }
      

      【讨论】:

        【解决方案15】:

        快速解决方案:

        class func deleteAllManagedObjects() {
        
                let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "mom")
                let mom = NSManagedObjectModel(contentsOfURL: modelURL)
        
                for entityName in mom.entitiesByName.keys {
                    let fr = NSFetchRequest(entityName: entityName as String)
                    let a = Utility.managedObjectContext().executeFetchRequest(fr, error: nil) as [NSManagedObject]
                    for mo in a {
                        Utility.managedObjectContext().deleteObject(mo)
                    }
                }
        
                Utility.managedObjectContext().save(nil)
            }
        

        【讨论】:

        • 对于 swift 2 let modelURL = NSBundle.mainBundle().URLForResource("some string", withExtension: "momd")!
        【解决方案16】:

        Swift 4/5,iOS 9+

        重建整个CoreData SQLite 文件将确保所有数据都被删除,因此所有实体都被删除。只需致电deleteAndRebuild()

        class CoreDataStack {
            // Change this
            static let datamodelName = "ProjectName"
            static let storeType = "sqlite"
        
            static let persistentContainer = NSPersistentContainer(name: datamodelName)
            private static let url: URL = {
                let url = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].appendingPathComponent("\(datamodelName).\(storeType)")
        
                assert(FileManager.default.fileExists(atPath: url.path))
        
                return url
            }()
        
            static func loadStores() {
                persistentContainer.loadPersistentStores(completionHandler: { (nsPersistentStoreDescription, error) in
                    if let error = error {
                        fatalError(error.localizedDescription)
                    }
                })
            }
        
            static func deleteAndRebuild() {
                try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: storeType, options: nil)
        
                loadStores()
            }
        }
        

        【讨论】:

        • 对于任何使用它的人,请注意,当那里没有 sql 文件时,它只会在“第一次”崩溃(我只是在我的回答中使用了“守卫”)
        【解决方案17】:

        作为在别处保存搜索的快速参考 - 在删除持久存储后重新创建持久存储可以通过以下方式完成:

        if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // do something with the error
        }
        

        【讨论】:

        • 我试过你的代码,但是xcode在这一行抛出了异常,所以你有什么要说的。
        【解决方案18】:

        这个问题有几个很好的答案。这是一个很好的简洁的。前两行删除 sqlite 数据库。然后 for: 循环删除 managedObjectContext 内存中的所有对象。

        NSURL *storeURL = [[(FXYAppDelegate*)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory] URLByAppendingPathComponent:@"AppName.sqlite"];
        [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
        for (NSManagedObject *ct in [self.managedObjectContext registeredObjects]) {
            [self.managedObjectContext deleteObject:ct];
        }
        

        【讨论】:

        • 我同意@MichaelDorner。在 AppDelegate 中添加太多内容会影响性能,并通过相互关联的依赖关系蜘蛛网使二进制文件的大小膨胀,其中 AppDelegate 突然需要包含在每个类中。如果您发现这种情况出现,请创建一个专门用于此目的的单独控制器。 AppDelegate 应该保留用于应用程序中的基本初始化和处理状态更改,仅此而已。
        【解决方案19】:

        这是一个删除您拥有的每个表中的每条记录的版本。

        斯威夫特 4

        static func resetDatabase() {
            do {
                try dataStore.persistentStoreCoordinator.managedObjectModel.entities.forEach { (entity) in
                    if let name = entity.name {
                        let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: name)
                        let request = NSBatchDeleteRequest(fetchRequest: fetch)
                        try mainContext.execute(request)
                    }
                }
        
                try mainContext.save()
            } catch {
                print("error resenting the database: \(error.localizedDescription)")
            }
        }
        

        【讨论】:

          【解决方案20】:

          您还可以找到所有实体名称,并按名称删除它们。它是一个较长的版本,但运行良好,这样您就不必使用持久存储

           - (void)clearCoreData
          {
          NSError *error;
          NSEntityDescription *des = [NSEntityDescription entityForName:@"Any_Entity_Name" inManagedObjectContext:_managedObjectContext];
          NSManagedObjectModel *model = [des managedObjectModel];
          NSArray *entityNames = [[model entities] valueForKey:@"name"];
          
          for (NSString *entityName in entityNames){
          
              NSFetchRequest *deleteAll = [NSFetchRequest fetchRequestWithEntityName:entityName];
              NSArray *matches = [self.database.managedObjectContext executeFetchRequest:deleteAll error:&error];
          
          }
              if (matches.count > 0){
                  for (id obj in matches){
          
                      [_managedObjectContext deleteObject:obj];
                  }
                 [self.database.managedObjectContext save:&error];
              }
          }
          

          对于“Any_Entity_Name”,只需给出您实体的任何一个名称,我们只需要找出您的实体所在的实体描述即可。 ValueForKey@"name" 将返回所有实体名称。最后别忘了保存。

          【讨论】:

            【解决方案21】:

            接受的答案是正确的,通过 NSFileManager 删除 URL 是正确的,但正如 iOS 5+ 编辑中所述,持久存储不仅由一个文件表示。对于 SQLite 存储,它是 *.sqlite、*.sqlite-shm 和 *.sqlite-wal ...幸运的是,从 iOS 7+ 开始,我们可以使用方法

            [NSPersistentStoreCoordinator +removeUbiquitousContentAndPersistentStoreAtURL:options:error:]

            要注意删除,所以代码应该是这样的:

            NSPersistentStore *store = ...;
            NSError *error;
            NSURL *storeURL = store.URL;
            NSString *storeName = ...;
            NSPersistentStoreCoordinator *storeCoordinator = ...;
            [storeCoordinator removePersistentStore:store error:&error];
            [NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:storeURL.path options:@{NSPersistentStoreUbiquitousContentNameKey: storeName} error:&error];
            

            【讨论】:

            • 您需要传递选项字典,特别是商店名称,例如:@{NSPersistentStoreUbiquitousContentNameKey: @"MyData"};
            【解决方案22】:

            Swift 5.1 解决方案

            public static func reset() {
                let coordinator = _persistentContainer.persistentStoreCoordinator
                for store in coordinator.persistentStores where store.url != nil {
                    try? coordinator.remove(store)
                    try? FileManager.default.removeItem(atPath: store.url!.path)
                }
            }
            

            【讨论】:

              【解决方案23】:

              适用于所有版本。传递实体名称并迭代以删除所有条目并保存上下文。

              func deleteData(entityToFetch: String, completion: @escaping(_ returned: Bool) ->()) {
                  var context = NSManagedObjectContext()
                  if #available(iOS 10.0, *) {
                      context = self.persistentContainer.viewContext
                  } else {
                      context = self.managedObjectContext
                  }
              
                  let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
                  fetchRequest.entity = NSEntityDescription.entity(forEntityName: entityToFetch, in: context)
                  fetchRequest.includesPropertyValues = false
                  do {
                      let results = try context.fetch(fetchRequest) as! [NSManagedObject]
                      for result in results {
                          context.delete(result)
                      }
                      try context.save()
                      completion(true)
                  } catch {
                      completion(false)
                      print("fetch error -\(error.localizedDescription)")
                  }
              }
              

              【讨论】:

                【解决方案24】:

                我经常使用的另一种方法(除了删除批处理请求)(基于应用程序要求)是重置持久存储。 iOS 10+ 和 Swift 的实现如下所示(假设您有一个 CoreDataManager 类):

                let persistentContainer: NSPersistentContainer = {
                    let container = NSPersistentContainer(name: "<Data-Model-Name>“)
                    container.loadPersistentStores(completionHandler: { (storeDescription, err) in
                        if let err = err {
                            fatalError("loading of store failed: \(err)")
                        }
                    })
                    return container
                }()
                
                func resetPersistentStore() {
                
                    if let persistentStore = persistentContainer.persistentStoreCoordinator.persistentStores.last {
                        let storeURL = persistentContainer.persistentStoreCoordinator.url(for: persistentStore)
                
                        do {
                            try persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: storeURL, ofType: NSSQLiteStoreType, options: nil)
                        } catch {
                            print("failed to destroy persistent store:", error.localizedDescription)
                        }
                
                        do {
                            try persistentContainer.persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
                        } catch {
                            print("failed to re-add persistent store:", error.localizedDescription)
                        }
                    }
                
                }
                

                这种方法的一个优点是它更简单,尤其是当您的核心数据中有大量实体的数据记录时。在这种情况下,批量删除请求会占用大量内存。

                【讨论】:

                  【解决方案25】:

                  似乎有两种方法:

                  假设您的核心数据堆栈有一个典型的单例。

                  import CoreData
                  public let core = Core.shared
                  public final class Core {
                      static let shared = Core()
                      var container: NSPersistentContainer!
                      private init() {
                          container = NSPersistentContainer(name: "stuff")
                          //deleteSql()
                          container.loadPersistentStores { storeDescription, error in
                              if let error = error { print("Error loading... \(error)") }
                          }
                          //deleteAll()
                      }
                      
                      func saveContext() { // typical save helper
                          if container.viewContext.hasChanges {
                              do { try container.viewContext.save()
                              } catch { print("Error saving... \(error)") }
                          }
                      }
                      
                  

                  然后...

                      func deleteSql() {
                          let url = FileManager.default.urls(
                             for: .applicationSupportDirectory,
                             in: .userDomainMask)[0].appendingPathComponent( "stuff.sqlite" )
                          
                          guard FileManager.default.fileExists(atPath: url.path) else {
                              print("nothing to delete!")
                              return
                          }
                          
                          do {
                              try container.persistentStoreCoordinator.destroyPersistentStore(
                                  at: url, ofType: "sqlite", options: nil)
                              print("totally scorched the sql file. you DO now have to LOAD again")
                          }
                          catch {
                              print("there was no sql file there!")
                          }
                      }
                      
                      func deleteAll() { // courtesy @Politta
                          for e in container.persistentStoreCoordinator.managedObjectModel.entities {
                              let r = NSBatchDeleteRequest(
                                fetchRequest: NSFetchRequest(entityName: e.name ?? ""))
                              let _ = try? container.viewContext.execute(r)
                          }
                          saveContext()
                          print("conventionally deleted everything from within core data. carry on")
                      }
                  }
                  

                  .

                  1。烧毁sql文件

                  感谢@J.Doe 的出色回答。你完全破坏了 sql 文件。

                  必须这样做

                  • 在加载核心数据之前,即在创建容器之后,但是
                  • 在实际加载商店之前。)

                  (请注意示例代码行“//deleteSql()”就在初始化之前。)

                  2。将核心数据中的所有内容一一删除

                  感谢@Politta 的出色回答。一旦核心数据启动并运行,您可以随时执行此操作。

                  (请注意示例代码行“//deleteAll()”是在初始化之后。)

                  方法一可能在开发过程中更有用。方法二可能在生产中更有用(在相对不寻常的情况下,由于某种原因您需要擦除所有内容)。

                  【讨论】:

                    【解决方案26】:

                    删除持久存储文件并设置新的持久存储协调器?

                    【讨论】:

                    • 执行清理不会删除持久存储文件,谢天谢地。如果属实,那将是一场灾难。
                    【解决方案27】:

                    从你的 fileURLPath 中删除 sqlite,然后构建。

                    【讨论】:

                    • 我的意思是应用安装的时候。
                    【解决方案28】:

                    假设您正在使用MagicalRecord 并有一个默认的持久性存储:

                    我不喜欢假设某些文件存在和/或要求输入实体名称或类的所有解决方案。这是从所有实体中删除所有数据的 Swift(2) 安全方法。删除后它也会重新创建一个新堆栈(我实际上不确定这部分的必要性)。

                    当您想要删除所有内容但有一个工作存储和 moc 来获取新数据(一旦用户登录......)时,这是“注销”风格的情况。

                    extension NSManagedObject {
                    
                        class func dropAllData() {
                    
                            MagicalRecord.saveWithBlock({ context in
                    
                                for name in NSManagedObjectModel.MR_defaultManagedObjectModel().entitiesByName.keys {
                                    do { try self.deleteAll(name, context: context) }
                                    catch { print("⚠️ ✏️ Error when deleting \(name): \(error)") }
                                }
                    
                                }) { done, err in
                                    MagicalRecord.cleanUp()
                                    MagicalRecord.setupCoreDataStackWithStoreNamed("myStoreName")
                            }
                        }
                    
                        private class func deleteAll(name: String, context ctx: NSManagedObjectContext) throws {
                            let all = NSFetchRequest(entityName: name)
                            all.includesPropertyValues = false
                    
                            let allObjs = try ctx.executeFetchRequest(all)
                            for obj in allObjs {
                                obj.MR_deleteEntityInContext(ctx)
                            }
                    
                        }
                    }
                    

                    【讨论】:

                      【解决方案29】:

                      使用这个

                      +(NSArray *)fetchDataFromEntity:(NSString *)entityName context:(NSManagedObjectContext *)context
                      {
                          NSFetchRequest * fetchRequest =[[NSFetchRequest alloc] init];
                          NSEntityDescription * CategoriesEntity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
                          [fetchRequest setEntity:CategoriesEntity];
                      
                          NSError * error;
                          NSInteger count = [context countForFetchRequest:fetchRequest error:&error];
                      
                          if (count && count>0) {
                      
                              NSArray * fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
                              if (fetchedObjects && fetchedObjects.count>0) {
                      
                                  return fetchedObjects;
                              }else
                                  return nil;
                      
                          }
                          else
                              return nil;
                      }
                      + (void)deleteObjectsOfArray:(NSMutableArray*)ary context:(NSManagedObjectContext *)context {
                          for (NSManagedObject * obj in ary) {
                              [context deleteObject:obj];
                          }
                          NSError *saveError = nil;
                          [context save:&saveError];
                      }
                      + (void)deleteEntity:(NSString *)entityName context:(NSManagedObjectContext *)context {
                          NSArray *listArray = [self fetchDataFromEntity:entityName context:context];
                          [self deleteObjectsOfArray:[NSMutableArray arrayWithArray:listArray] context:context];
                      }
                      

                      【讨论】:

                        【解决方案30】:

                        我采用了 Grouchal 的代码,为了加快速度,我使用了并发模式的枚举 (NSEnumerationConcurrent),与 for 循环相比,它的速度要快一些(在我的应用程序中,我为测试人员添加了此功能,以便他们可以清除数据和做测试用例而不是删除和安装应用程序)

                        - (void)resetObjects
                        {
                            [self deleteAllObjectsInEntity:@"Entity1"];
                            [self deleteAllObjectsInEntity:@"Entity2"];
                            [self deleteAllObjectsInEntity:@"Entity3"];
                            [self deleteAllObjectsInEntity:@"Entity4"];
                        }
                        
                        -(void) deleteAllObjectsInEntity:(NSString*) entityName
                        {
                            MainDataContext *coreDataContext = [MainDataContext sharedInstance];
                            NSManagedObjectContext *currentContext = coreDataContext.managedObjectContext;
                            NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
                            NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:currentContext];
                            [fetchRequest setEntity:entity];
                        
                            NSError *error;
                            NSArray *items = [currentContext executeFetchRequest:fetchRequest error:&error];
                        
                            [items enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSManagedObject * obj, NSUInteger idx, BOOL *stop) {
                                [currentContext deleteObject:obj];
                            }];
                        
                        
                            if (![currentContext save:&error]) {
                                NSLog(@"Error deleting %@ - error:%@",entityName,error);
                            }
                        }
                        

                        【讨论】:

                          猜你喜欢
                          • 2015-04-11
                          • 1970-01-01
                          • 2018-10-16
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2013-08-18
                          相关资源
                          最近更新 更多