8

对于我的应用程序,我从核心数据存储中获取了很多对象,这会导致应用程序冻结并阻止所有 UI 输入。我想在应用程序保持响应时在后台进行获取,并且tableview仅在数据可用时更新。
为此,我设置了一个新NSManagedObjectContext的,NSPrivateQueueConcurrencyType并将其作为主 MOC 的子级。虽然我的设置正在返回所需的对象,但似乎所有处理仍在冻结 UI,并且与在主队列上发生所有事情的旧代码的响应能力几乎没有区别。

根据这篇文章,子上下文设置无助于保持 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);
            }];
        }
    }];
4

1 回答 1

19

首先,了解究竟是MR_findAllInContext:做什么的会很有帮助。最好的解决方案是以更有效的方式解决这个问题。谓词看起来如何?您是否在请求中指定批量大小?您是否对要查询的属性使用索引?你的数据集有多大?如果没有更多细节,很难判断是否有更好的解决方案。

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

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

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

在主线程上下文后面添加背景上下文不会提高性能。嵌套上下文只是不以这种方式使用。

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

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

于 2013-09-04T20:58:20.537 回答