我的应用程序需要从我的Web API导入对象(通常超过5000个对象),同时仍然与数据库交互。目前,我将API设置为每个API请求返回100个对象。问题是我的性能受到了巨大冲击。它可以采取> 4秒导入所有数据。大部分时间都是在调用save函数时花掉的。我已成功将导入推送到后台线程。但是当我在每个api请求结束时将主上下文保存在主线程上时,可能需要1秒以上才能保存,这会暂停所有滚动,动画等。我可以做什么来保存主要上下文的背景?
更新:以下是一些示例代码
-(void) importLoop:(NSManagedObjectContext*)mainContext complete:(dispatch_block_t) complete{
[self apiRequest:^(NSArray *objects) {
if (objects.count == 0){ // nothing to load.
dispatch_async(dispatch_get_main_queue(), complete);
return;
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
NSManagedObjectContext* bgContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[bgContext setParentContext:mainContext];
[bgContext performBlock:^{
for (id object in objects){
// import data. This can take > 4 seconds
[bgContext save:nil]; // This can take > 1 second
// Note: This save merges the data to the main moc... but does not save the data to disk
}
[mainContext performBlock:^{
[mainContext save:nil]; // This can take > 1 second on main thread
[self importLoop:mainContext complete:complete]; // import next batch
}];
}];
});
}];
}
更新 根据@Wain answer,我需要设置以下内容
mainMoc - > mainThreadMoc - > bgMoc
哪里
好了,我已经有了这个设置,我有以下问题...当我对mainThreadMoc进行更改时,我如何让bgMoc知道它。我有以下为NSManagedObjectContextDidSaveNotification
- (void)managedObjectContextDidSaveNotification:(NSNotification *)notification
{
NSManagedObjectContext *savedContext = [notification object];
// ignore change notifications for the main MOC
if (self.mainMoc == savedContext)
{
return;
}
if (self.mainMoc.persistentStoreCoordinator != savedContext.persistentStoreCoordinator)
{
// that's another database
return;
}
if (savedContext == self.mainThreadMoc){
[self.mainMoc performBlock:^{
[self.mainMoc mergeChangesFromContextDidSaveNotification:notification];
}];
}else if (savedContext == self.bgMoc){
[self.mainThreadMoc performBlock:^{
[self.mainThreadMoc mergeChangesFromContextDidSaveNotification:notification];
}];
}
}
更新:我发现上面提到的上下文链接,如果我像在初始示例中那样创建背景上下文,那么事情似乎正在发挥作用。保存后台线程时仍有明显的延迟(我认为这是将更改传播到主线程的结果)。然而,这是性能的巨大改进。
答案 0 :(得分:2)
我不会通过引入额外的私有队列父MOC来开始。
充其量它会略微减少在主线程上花费的总时间,同时增加完成导入的总挂钟时间。
我还不建议在核心数据之上建立第三方框架,而您仍然需要掌握核心数据框架。
关于处理NSManagedObjectContextDidSaveNotification
的问题,如果您在第一个示例中显示的每个摄取块临时创建了新的bgContext
,则无需处理这些通知所有这些都是因为在子上下文中立即调用save:
并透明地将更改传播到父级。
至于原始问题和示例,对于100个对象,调用save:
不应该花费1秒钟。
在了解为什么需要1秒钟来保存100个对象之前,您不应该考虑架构更改(例如不同的上下文安排)。
将您的应用程序连接到乐器并让它告诉您一直在占用什么。答案可能让你大吃一惊。
答案 1 :(得分:0)
您需要保存到持久性存储中,而不一定是从主上下文中保存。
您应该有一个私有队列上下文,它是主上下文的父级和后台上下文,因此您可以在不影响主线程的情况下进行保存,然后将更改合并到主上下文中。主要是指主线程,而非主要所有权。