ios - 核心数据后台处理仍然阻塞UI

标签 ios multithreading core-data concurrency

对于我的应用程序,我正在从核心数据存储中获取大量对象,这会导致应用程序卡住并阻止所有 UI 输入。我想在应用保持响应的同时在后台进行抓取,并仅在数据可用时更新 tableview
以此目的 我已经使用 NSPrivateQueueConcurrencyType 设置了一个新的 NSManagedObjectContext 并将其作为主要 MOC 的子项。虽然我的设置正在返回所需的对象,但似乎所有处理仍在卡住 UI,并且与旧代码的响应几乎没有区别,旧代码的一切都发生在主队列上。

根据这个article子上下文设置无助于保持 UI 响应,而我在网上的其他任何地方都读过如果你想从繁重的处理中减轻主队列,这是要走的路吗?我错过了什么吗?

  NSManagedObjectContext *mainMOC = self.mainObjectContext;
  NSManagedObjectContext *backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

    [backgroundMOC setParentContext:mainMOC];
    [backgroundMOC performBlock:^{

        //query for objects
        NSArray *results = [Product MR_findAllInContext:backgroundMOC];

            NSError *childError = nil; 
            [backgroundMOC save:&childError]; 

        if ( [results count] > 0 ) {
            //get objectIDs
            NSMutableArray *objectIDs = [NSMutableArray array]
            for (NSManagedObject *object in results) {
            [objectIDs addObject:[object objectID]];
            }

            [mainMOC performBlock:^{
                //refetch objects on the mainQueue
                NSMutableArray *persons = [NSMutableArray array]
                for (NSManagedObjectID *objectID in objectIDs) {
                [persons addObject:(Person*)[mainMOC objectWithID:objectID]];
                }
                 //return result
                 if (self.callBack)
                 self.callBack(persons);
            }];
        }
    }];

最佳答案

首先,了解 MR_findAllInContext: 的确切作用会很有帮助。最好的解决方案是以更有效的方式解决这个问题。谓词是什么样子的?您是否在请求中指定了批量大小?你在查询的属性上使用索引吗?你的数据集的大小是多少?如果没有更多细节,很难判断是否有更好的解决方案。

您当前的方法似乎对嵌套上下文的工作方式存在相当普遍的误解。

问题在于上下文的设置方式。由于您使背景上下文成为主要上下文的子上下文,因此您在后台上下文中所做的一切都必须“通过”主要上下文。

保存后台上下文将导致将对象图中的所有更改推送到主上下文,然后主上下文也必须保存以持久保存更改。在后台上下文中执行获取请求会将其转发到主上下文,主上下文会将其发送到持久存储协调器并将结果同步 交回后台上下文。后台上下文(获取或保存)上的任何请求都将锁定父上下文并阻塞主线程,这与直接在主上下文上执行请求时类似。

在主线程上下文后面添加后台上下文不会提高性能。嵌套上下文不适合以这种方式使用。

为了实现你想要的,你必须在独立于主上下文的上下文中执行获取请求,例如与 PSC 直接关联的背景上下文。在这种情况下,获取请求仍将锁定 PSC。这意味着由于 PSC 上的锁争用,在此期间在主上下文上执行请求仍会阻塞主线程。但至少一般情况下不会阻塞主线程。

请注意,当您将生成的 objectID 传递给主上下文时,使用 objectWithID: 获取对象,然后访问这些对象,您仍然依赖 PSC 的行缓存来保存数据以使其快速。由于对象一开始会出错,如果行缓存不再有数据,Core Data 将不得不为每个对象转到磁盘。这将非常缓慢。您可以使用 Instruments 检查缓存命中和未命中。

关于ios - 核心数据后台处理仍然阻塞UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18616797/

相关文章:

ios - CoreData对象之间的关系

core-data - 在 Swift 中从 CoreData 中获取最新的项目

ios - Baker Ebook Framework:如何将“book”文件夹正确打包为.hpub格式?

javascript - 在适用于所有浏览器和 iOS 的网站上录制音频

ios - Swift 中的 NSSortDescriptor - 按距离下一个生日剩余的天数排序

c - 将主线程从 sleep 中唤醒

iphone - reloadRowsAtIndexPaths 后未调用 cellForRowAtIndexPath

ios - 代表无法调用第二个 View Controller

java - Java 中的 StampedLock 是什么?

vb.net - 在 VB.NET 的新线程上引发事件