【问题标题】:Core Data: Background fetch, NSFetchedResultsController and Sorting time核心数据:后台获取、NSFetchedResultsController 和排序时间
【发布时间】:2011-04-14 09:43:54
【问题描述】:

我遇到的问题如下:

我有一个 UITableView,我使用来自 NSFetchedResultsController 的数据提供数据,该 NSFetchedResultsController 从核心数据中检索大约 6000 行。 NSFetchRequestfetchBatchSize 设置为 20,如果我不应用任何 NSSortDescriptor,则获取速度足够快,不会阻塞 UI 线程。

但是,我确实需要显示那些按字母顺序排序的行,我使用以下 NSSortDescriptor:

[[[NSSortDescriptor alloc] initWithKey:@"optionText" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];

当事情发生变化时,提取操作现在需要大约 3 秒才能完成,因为正在对 6000 行进行排序。显然,在这几秒钟内,用户界面被阻塞,用户体验很糟糕。

我知道我可以在后台线程中进行提取,然后将对象 ID 传递给主线程,但在这种情况下,我怎么还能在主线程中使用 NSFetchedResultsController(我也用它来观察数据的变化)?

我也有 indexed 我正在排序的属性,但这只会优化查找而不是排序性能。

任何想法将不胜感激,谢谢!

【问题讨论】:

  • 愚蠢的问题,但我想您不能在将数据加载到 Core Data 之前对其进行预排序?
  • 愚蠢的问题,在您运行获取请求时 managedObjectContext.hasChanges 的值是多少?

标签: sorting core-data background nsfetchedresultscontroller


【解决方案1】:

使用 NSFetchRequest 的 batchSize 属性怎么样?

如果您设置非零批量大小,则返回的对象集合 当 fetch 被执行时被分成多个批次。当提取是 执行,整个请求被评估和所有的身份 记录匹配对象,但不超过 batchSize 对象的数据 将一次从持久存储中获取。数组 从执行请求返回的将是一个代理对象 透明地根据需要对批次进行故障处理。 (在数据库术语中,这是一个 内存中的光标。)

【讨论】:

    【解决方案2】:

    我在使用单独的 NSManagedObjectContext 的 NSOperation 中执行后台批量导入。我定期保存第二个上下文,它会触发一个通知来更新我的 NSFetchedResultsController 连接到的主 NSManagedContext。

    也许类似的技术可以应用于您的 fetch

    这里有一篇关于可可是我女朋友的文章:

    http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/

    核心数据编程指南“批量导入”中也提到了该技​​术

    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174-SW1

    【讨论】:

      【解决方案3】:

      首先,NSFetchedResultsController 通常用于主线程。并且它不支持后台获取直到现在Apple发布iOS 6。

      所以当你调用 NSFetchedResultController 的 performFectch 时,你必须“阻塞”主线程一段时间。但是,我们确实希望时间最短。

      (据我所知,您必须为 NSFetchedResultController 设置一个排序描述符。所以我不确定您是如何在没有设置排序描述符的情况下使其工作的。看看类参考)

      我不确定您是否使用 Sqlite Store。如果是这样,我简直不敢相信你的排序描述符工作。 (看看核心数据编程指南:故障排除部分)。如果没有,在内存中保留这么多数据不是一个好主意

      终于我们明白了为什么它很慢。这种使用“localizedCaseInsensitiveCompare:”的排序会使您的获取速度变慢,因为比较 Unicode 字符串会很慢。 (在 WWDC 2010 Core Data Performance on iPhone 中提到)。

      与许多其他应用程序一样,您应该根据“optionText”创建一个非 Unicode 字符串字段/属性,并根据该非 Unicode 字符串属性进行排序。

      【讨论】:

        【解决方案4】:

        使用缓存可能有助于获得更好的性能。

        我遇到了同样的问题,并意识到在第一次调用中提取需要超过 3 秒,但执行两次提取会立即显示结果。

        【讨论】:

        • 是的,缓存有助于任何后续提取,但第一个仍然非常慢,明显阻塞了 UI 线程。
        【解决方案5】:

        就用户体验而言,在一个表中显示 6000 行可能不是最佳解决方案。也许您应该在之前添加一个过滤器表。类似于地址簿中的组。如果您设法将每个过滤器选项的行数减少到更易于管理的数量,这可能会带来更好的用户体验。这将减少加载时间和滚动时间。

        我不知道你在显示什么样的数据,所以也许没有办法,只能在一个长列表中显示所有数据。对于人们,您可以添加性别和年龄组选项。对于汽车,您可以按品牌和型号添加过滤器....

        【讨论】:

        • 我知道这不是最好的 UI 设计,但这是一个要求,客户不愿意更改它。我真的认为 NSFetchedResultsController 应该支持后台提取。不过感谢您的评论。
        【解决方案6】:

        您是否尝试过在后台运行 performFetch: 方法,或者使用

        [controller performSelectorInBackground:@selector(performFetch) withObject:nil];
        

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
            [controller performFetch];
        });
        

        【讨论】:

        • 这不是一个安全的解决方案。 NSFetchedResultsController 有一个 managedObjectContext 不是线程安全的。
        • 我同意@Tal Bereznitskey。还有其他想法吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多