我有以下核心数据堆栈:
NSMainQueueConcurrencyType
NSManagedObjectContexts
的多个临时NSPrivateQueueConcurrencyType
(按需创建)。他们的父managedObjectContext设置为主要的managedObjectContext 到目前为止,我使用主要的managedObjectContext进行提取,使用私有的managedObjectContexts进行数据导入,因为要保存很多数据并且我不想阻止主线程。到目前为止,这对我来说非常好。
现在我想实现我的应用搜索大量数据的全文搜索。我知道这在计算上是昂贵的,因此我想在后台执行此操作。
- (void)filterConfigurationsInBackground
{
NSManagedObjectContext *temporaryContext = [[MVADataManager sharedInstance] privateContext];
[temporaryContext performBlock:^{
NSArray *filteredConfigurationsObjects =
[temporaryContext executeFetchRequest:request error:&error];
NSArray *filteredConfigurationsObjectIDs = [filteredConfigurationsObjects valueForKey:@"objectID"];
NSManagedObjectContext *mainContext = [[MVADataManager sharedInstance] managedObjectContext];
[mainContext performBlock:^{
NSMutableArray *result = [NSMutableArray array];
for (NSManagedObjectID *objectID in filteredConfigurationsObjectIDs)
{
NSError *error = nil;
NSManagedObject *configuration = [context existingObjectWithID:objectID error:&error];
if (configuration == nil)
{
DLog(@"Invalid objectID: %@", [error localizedDescription]);
}
else
{
[result addObject:configuration];
}
}
[self setFilteredConfigurations:result];
if ([self.tableView numberOfSections] == 1)
{
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
else
{
[self.tableView reloadData];
}
[self updateTitle];
}];
}];
}
这确实有效,但是获取非常慢并且UI冻结了,这显然不应该发生。我的理解是,由于我在私有队列上执行实际的提取和过滤,因此根本不应该阻塞主线程。时间分析器没有帮助,只显示99%的“主”运行时间。为什么这段代码会阻塞主线程?
通过设置断点,我发现了对objectIDs的获取是代码中减慢一切的一部分。在断点处,调试器显示我们在后台线程上,UI冻结。 Xcode中的CPU报告显示,所有工作都在主线程上完成
我找到了解决此问题的方法,但我仍然不知道究竟是什么原因造成的。我发现核心数据似乎很难与我的相当复杂的复合谓词进行全文搜索。 (除了全文搜索,我的谓词还对这些对象进行了一些基本的过滤。)
因此,如果我首先使用基本过滤谓词执行核心数据提取,然后通过filteredArrayUsingPredicate:
应用全文搜索谓词部分,则所有内容都可以在后台完成,而不会阻塞主线程。我仍然不知道为什么这个问题仍然存在,但我现在对这个解决方法感到满意。直到我有时间(和神经)深入研究,我才回答这个问题。