问题 : 如何让我的子上下文看到在父上下文上持久存在的更改,以便它们触发我的 NSFetpedResultsController 来更新 UI?
这是设置:
您有一个应用程序,它可以下载并添加大量 XML 数据(大约200万条记录,每条记录的大小大致相当于一段正常文本的大小)。Sqlite 文件大小约为500MB。将这些内容添加到 Core Data 需要时间,但是您希望用户能够在数据以递增方式加载到数据存储中时使用这个应用程序。大量的数据被移动,这对用户来说是不可见和不可察觉的,所以没有挂起,没有紧张: 滚动就像黄油一样。尽管如此,这个应用程序更有用,添加的数据越多,所以我们不能永远等待数据被添加到核心数据存储。在代码中,这意味着我真的希望在导入代码中避免这样的代码:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
这个应用程序只支持 iOS5,所以它需要支持的最慢的设备是 iPhone3GS。
以下是我到目前为止用来开发我当前解决方案的资源:
IDeveloper TV-Mac、 iPhone 和 iPad 的核心数据更新
我有3个 NSManagedObjectContext 实例:
Master ManagedObjectContext -这个上下文具有 NSPersisentStore 协调器,负责将文件保存到磁盘。我这样做是为了我的保存可以是异步的,因此非常快。我在发射时创建它,像这样:
masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
MainManagedObjectContext -这是 UI 到处使用的上下文。它是 master ManagedObjectContext 的子代。我是这样创造的:
mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[mainManagedObjectContext setUndoManager:nil];
[mainManagedObjectContext setParentContext:masterManagedObjectContext];
BackoundContext -这个上下文是在我的 NSOperation 子类中创建的,它负责将 XML 数据导入到 Core Data 中。我在操作的 main 方法中创建它,并将它链接到那里的主上下文。
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 不会更新。
我有一个简单的 UIViewController 和一个 UITableView,它使用 NSFetcheResultsController 提供数据。当 Import 过程完成时,NSFetchResultsController 不会看到来自父/主上下文的更改,因此 UI 不会像我习惯看到的那样自动更新。如果我从堆栈中弹出 UIViewController 并再次加载它,所有的数据都在那里。
问题 : 如何让我的子上下文看到在父上下文上持久存在的更改,以便它们触发我的 NSFetpedResultsController 来更新 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];
}