问题:如何获取子上下文以查看更改在父上下文中的持久性,以便它们触发我的NSFetchedResultsController更新UI?
设置如下:
您有一个应用程序可以下载并添加大量XML数据(大约200万条记录,每个记录的大小均与正常文本的大小相同)。.sqlite文件的大小约为500 MB。将此内容添加到Core Data需要花费时间,但是您希望用户能够在数据逐步加载到数据存储中时使用该应用程序。用户必须看不见并且无法感知大量数据在四处移动,因此不会挂起,也不会抖动:滚动像黄油一样。尽管如此,该应用程序仍然有用,它添加了更多数据,因此我们不能永远等待将数据添加到Core Data存储中。在代码中,这意味着我真的很想避免在导入代码中使用如下代码:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
该应用程序仅是iOS 5,因此它需要支持的最慢的设备是iPhone 3GS。
这是到目前为止我用来开发当前解决方案的资源:
- 使用自动释放池使内存减少
- 关系成本。导入平面,然后在最后修补关系
- 不要查询您是否可以提供帮助,它会以O(n ^ 2)的速度降低速度
- 批量导入:保存,重置,清空和重复
- 关闭导入时的撤消管理器
- 使用3种上下文:主,主和限制上下文类型
iDeveloper TV-Mac,iPhone和iPad的核心数据更新
- 使用performBlock在其他队列上运行保存可以使事情变得更快。
- 加密会使速度变慢,如果可以,请将其关闭。
- 您可以通过给当前的运行循环一些时间来减慢导入速度,从而使用户感觉平稳。
- 示例代码证明,可以进行大量导入并保持UI响应,但是速度不如3个上下文和异步保存到磁盘的速度快。
我目前的解决方案
我有3个NSManagedObjectContext实例:
masterManagedObjectContext-这是具有NSPersistentStoreCoordinator并负责保存到磁盘的上下文。我这样做是为了使我的保存可以是异步的,因此非常快。我在启动时就这样创建它:
masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
mainManagedObjectContext-这是UI随处使用的上下文。它是masterManagedObjectContext的子级。我这样创建它:
mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[mainManagedObjectContext setUndoManager:nil];
[mainManagedObjectContext setParentContext:masterManagedObjectContext];
backgroundContext-此上下文在我的NSOperation子类中创建,该子类负责将XML数据导入Core Data。我在操作的main方法中创建它,并将其链接到那里的master上下文。
backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[backgroundContext setUndoManager:nil];
[backgroundContext setParentContext:masterManagedObjectContext];
这实际上非常非常快。仅通过执行这3个上下文设置,我就能将导入速度提高10倍以上!老实说,这很难让人相信。(此基本设计应该是标准核心数据模板的一部分...)
在导入过程中,我保存了2种不同的方式。我在后台上下文中保存的每1000个项目:
BOOL saveSuccess = [backgroundContext save:&error];
然后,在导入过程结束时,我保存了主/父上下文,这表面上将修改推送到其他子上下文,包括主上下文:
[masterManagedObjectContext performBlock:^{
NSError *parentContextError = nil;
BOOL parentContextSaveSuccess = [masterManagedObjectContext save:&parentContextError];
}];
问题:问题是直到重新加载视图,UI才会更新。
我有一个带有UITableView的简单UIViewController,正在使用NSFetchedResultsController馈入数据。导入过程完成后,NSFetchedResultsController不会从父/主上下文中看到任何更改,因此UI不会像我以前所看到的那样自动更新。如果我将UIViewController从堆栈中弹出并再次加载,则所有数据都在那里。
问题:如何获取子上下文以查看更改在父上下文中的持久性,以便它们触发我的NSFetchedResultsController更新UI?
我尝试了以下只是挂起应用程序的操作:
- (void)saveMasterContext {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
NSError *error = nil;
BOOL saveSuccess = [masterManagedObjectContext save:&error];
[notificationCenter removeObserver:self name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
}
- (void)contextChanged:(NSNotification*)notification
{
if ([notification object] == mainManagedObjectContext) return;
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
return;
}
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}