核心数据后台处理仍然阻止UI

Oys*_*sio 6 concurrency multithreading core-data ios

对于我的应用程序,我从核心数据存储中获取了很多对象,这会导致应用程序冻结并阻止所有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);
            }];
        }
    }];
Run Code Online (Sandbox Code Playgroud)

小智 15

首先,了解MR_findAllInContext:确切的内容会很有帮助.最好的解决方案是以更有效的方式解决这个问题.谓词是怎样的?您是否在请求中指定了批量大小?您是否在要查询的属性上使用索引?您的数据集大小是多少?没有更多细节,很难说是否有更好的解决方案.

你现在的方法遭受了似乎是对嵌套上下文如何工作的相当广泛的误解.

问题是上下文的设置方式.由于您将背景上下文作为主上下文的子项,因此您在后台上下文中执行的所有操作都必须"遍历"主上下文.

保存背景上下文将导致将对象图中的所有更改推送到主上下文,然后必须保存以保持更改.在后台上下文上执行获取请求会将其转发到主上下文,主上下文会将其发送到持久性存储协调器并同步将结果交还给后台上下文.对后台上下文(获取或保存)的任何请求都将锁定父上下文,并且还会阻止主线程,就像直接在主上下文中执行请求一样.

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

为了实现您想要的功能,您必须在独立于主上下文的上下文上执行获取请求,例如与PSC直接关联的后台上下文.在这种情况下,获取请求仍将锁定PSC.这意味着在此期间在主上下文上执行请求仍将阻塞主线程,因为PSC上存在锁争用.但至少主线程一般不会被阻止.

请注意,当您将生成的objectID传递给主上下文,获取其中的对象objectWithID:然后访问这些对象时,您依靠PSC的行缓存仍然保存数据以使其快速.由于对象最初会出现故障,因此如果行缓存不再具有数据,则Core Data必须转到每个对象的磁盘.这将非常缓慢.您可以向Instruments查询缓存命中和未命中.