【问题标题】:Core Data: Interrupt executing NSFetchRequest核心数据:中断执行 NSFetchRequest
【发布时间】:2026-02-18 19:45:01
【问题描述】:

一直在寻找这个:

在Core Data中,有没有办法中断/停止/取消和执行NSFetchRequest?

我正在一个 iPhone 应用程序中实现增量搜索,并且我尝试了各种优化它的方法,但这还不够(我有 42,000 条记录),所以我必须在 NSOperation 中运行它。当输入一个新字符时,我需要取消之前的 fetchRequest,但是 [nsoperation cancel] 什么都不做。

另一种方法可能是将我正在搜索的字段移动到其他一些可中断的索引中,可能在内存中,或者可能是一个单独的 sqlite3 数据库,这似乎可以用 sqlite_interrupt 中断。

【问题讨论】:

    标签: iphone search core-data


    【解决方案1】:

    您的问题的直接答案是否定的。对于您当前的设计,您最好的选择是在操作中执行它们,但是您需要担心线程障碍并减慢您的速度。请记住,如果您的操作没有在主线程上运行,那么您需要一个单独的NSManagedObjectContext 用于该操作,否则您将遇到线程问题。

    更好的问题:为什么要为每个字符进行新的提取?

    如果您已经从之前的搜索中获取了获取结果并且用户没有删除字符,则只需获取现有结果并针对 NSArray 运行您的谓词。这将进一步细化搜索,而不是每次都去磁盘。由于它在内存中,它会非常快。

    在实现搜索字段时考虑以下选项:

    • 只在第一个字符上敲击磁盘
    • 仅当从搜索框中删除字符时才点击磁盘
    • 考虑预加载 objectID 和可搜索属性以避免磁盘命中。

    根据您搜索的内容(并且有一些方法可以重新规范化 Core Data 存储以改进搜索),您可以将相当多的内容预加载到内存中。即使有 42K 记录,如果搜索属性足够小,您也可以将它们全部加载到内存中。

    如果用户从按“A”开始,您可能还是需要测试该用例。

    NSFetchRequest 的哪一部分很慢?访问 SQLite 数据库或将数据加载到内存中?根据您的回答,您可以直接提高搜索性能。

    【讨论】:

    • 如果在搜索文本中插入了任何字符,您还应该“点击磁盘”。例如,用户可以键入“fooar”,然后通过插入缺失的字符来更正它,然后下一个搜索将是“foobar”。
    【解决方案2】:

    我的解决方案是让查询操作继续运行,但在发送事件以更新 UI 之前检查它们是否已被取消。

    这并不完美,因为您仍然可以运行大量查询操作,其结果永远不会被使用,但它仍然要快一些。

    【讨论】:

      【解决方案3】:

      其实我和你有同样的问题。为了解决它,我使用performSelector:afterDelay: 方法

      这有点棘手,但是当用户快速输入 3 个字母时,我不想发送 3 个请求,而只在用户完成输入时发送一个请求。我设置了 0.5 或更多的小延迟。

      并使用此代码:

      [NSObject cancelPreviousPerformRequestsWithTarget:self];
      [self performSelector:@selector(fetchSearch:) withObject:searchQuery afterDelay:0.5];
      

      如果用户打字快,它会取消之前的请求,只发送最后一个。

      【讨论】:

        【解决方案4】:

        简短的回答 - 不,不是直接的,抱歉。

        长答案 - 是的,但你必须做很多事情或工作才能做到这一点

        您需要在后台线程中运行它(听起来您已经在通过 NSOperation 执行此操作)

        在您的 fetch 中,将限制设置为一次获取​​ 20 个结果并循环运行。每次通过循环,将它得到的结果添加到一个数组中。每次 fetch 得到每组结果时,检查是否要取消请求。

        【讨论】:

        • 后者不起作用,因为对于有序查询,获取前 20 个所需的时间几乎与第一个 n 一样多。
        • 对于有序查询,如果您设置了适当的索引,则不会花费更长的时间。