【问题标题】:Deleting Core Data after X amount of daysX 天后删除核心数据
【发布时间】:2015-01-07 20:59:16
【问题描述】:

所以我在 Core Data 中有一堆对象,并希望它们在 X 天后自动删除(这将基于 NSDate)。我做了一些搜索,似乎您一次只能删除一个核心数据对象,而不是一组,更不用说基于某个日期的那些。我在想也许有一个循环通过每个对象运行——但这似乎是处理器非常重的。关于我应该在哪里做这件事的任何想法?谢谢。

【问题讨论】:

  • @tkanzakic 这不是重复的,他知道如何在循环中删除多个对象。他特别询问如果这样做会慢得令人无法接受并且让应用程序完全无响应时该怎么做。
  • 你看过iOS 8中Core Data新增的批量更新功能吗?它使您可以更快地执行此类性能密集型操作。

标签: ios core-data swift


【解决方案1】:

循环一个一个地删除对象是正确的做法。

在 Core Data 中删除对象是极其繁重的处理器。如果这是一个问题,那么 Core Data 不适合你的项目,你应该使用别的东西。我推荐FCModel,作为一种非常有效的轻量级替代品。

如果您要坚持使用 Core Data,最好在后台 NSOperationQueue 上执行大型操作,这样主应用程序在删除对象时不会被锁定。您需要非常小心跨多个线程的 Core Data,方法是为每个线程拥有一个单独的托管对象上下文,两者都使用相同的持久存储协调器。永远不要跨线程共享托管对象,但您可以共享 objectID,以在另一个托管对象上下文中获取同一数据库记录的第二个副本。

基本上,您的后台线程会创建一个新上下文,删除循环中的所有对象,然后(最好在主线程上,参见文档)保存后台线程上下文。这将合并您的更改,除非发生冲突(两个上下文都修改同一个对象)——在那种情况下,您有几个选择,我只是中止整个删除操作并重新开始。

Apple 为所有问题提供了良好的文档,并在此处提供了示例代码:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdConcurrency.html

这有点令人生畏,您需要做一些认真的功课,但是一旦您了解了一切是如何工作的,实际的代码就会非常简单。或者只使用专为快速批处理操作而设计的 FCModel。

【讨论】:

  • FCModel 在它是一个 SQL 数据库的意义上是一种替代方案。 Core Data 不是数据库;它是一个对象关系图,可以选择将其数据保存在 SQLite 数据库中。
  • @Abizern 数据库是“为便于搜索和检索而安排的数据集合。”因此,Core Data 是一个数据库。同样在 iOS 上,SQLite 是唯一的数据持久性选项,在 OS X 上可用的其他两个选项在 iOS 上是不允许的。二进制数据存储和 XML 使用过多 RAM,可能会导致磁盘抖动,从而导致闪存过早失效。
  • 我会选择 FCModel,但我已经设置了核心数据和使用该应用程序的用户群 - 据我所知,您无法将数据从 Core Data 迁移到 FCModel。有人提到 iOS 8 中的核心数据批量更新,这样有什么好处吗? (我对这一切有点陌生)
  • @Yismo 你可以从 Core Data 迁移到 FCModel,但这并不容易。我同意,坚持使用 Core Data。测试删除的速度有多慢,如果速度很慢,请按照我的建议使用后台队列。
  • @AbhiBeckert 我想说的是,虽然它将数据存储在数据库中(实现细节),但它不是数据库。你不能像访问数据库一样访问它(或者至少你不应该)
【解决方案2】:

它并不像你想象的那么重 :)(当然这取决于数据量)

随意使用循环

- (void)deleteAllObjects
{
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];

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

    if (![self.managedObjectContext save:&error]) {
        NSLog(@"Error occurred");
    }
}  
}

【讨论】:

  • 处理器很重。我编写的应用程序可能需要长达 5 分钟的时间来执行 for { delete } 循环。 FCModel 中的相同操作大约需要 0.5 秒。
  • 是的,FCModel 当然是更好的方法,但有些人只想使用 Core Data
  • 你知道我将如何进行日期检查 - 看看它是否早于某个日期吗?
  • 嗯,IMO 你必须为你的实体添加例如 creationDate 属性,并使用 NSPredicate 来创建早于...
  • 所以我知道了,我只是对 NSPredicate 部分有点困惑
【解决方案3】:

正如其他人所指出的,迭代对象是在 Core Data 中实际删除对象的唯一方法。这是 Core Data 的方法失败的用例之一,因为它没有针对这种使用进行优化。

但有一些方法可以避免在您的应用中出现不必要的延迟,这样用户就不必在您的代码发出大量删除请求时等待。

如果您有很多需要删除的对象,并且您不想等到该过程完成,您可以先假装初始删除,然后在方便时进行实际删除。比如:

  1. 向名为toBeDeleted 之类的实体类型添加自定义布尔属性,默认值为NO
  2. 当您有一堆对象要删除时,使用NSBatchUpdateRequest(iOS 8 中的新功能)在一个步骤中将所有对象上的toBeDeleted 设置为YES。这个类大多没有文档,所以查看头文件或BNR blog post about it。您将指定属性名称和新属性值,Core Data 将进行大规模、快速更新。
  3. 确保您的所有提取请求都检查toBeDeleted 是否为NO。现在标记为删除的对象在提取时将被排除,即使它们仍然存在。
  4. 在某个时间点 - 稍后但很快 - 在后台运行一些代码来获取和删除将 toBeDeleted 设置为 YES 的对象。

【讨论】:

    猜你喜欢
    • 2017-03-20
    • 1970-01-01
    • 2012-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多