我有一个应用程序设计的问题,我希望有人可以帮助。
让我们做一个非常简单的设置:Core Data应用程序显示来自服务器的新闻项。
-
主线程/UI有一个被所有视图控制器用来显示数据的托管对象上下文。
-
一个NSOperation运行在后台检查服务器,与它自己的上下文,在同一个持久存储。
我想合并背景上下文的变化,所以我使用NSManagedObjectContextObjectsDidChangeNotification。
根据Apple docs:
一些系统框架在内部使用Core Data。如果您注册从所有上下文中接收这些通知(通过将nil作为对象参数传递给addObserver…方法),那么您可能会收到难以处理的意外通知。
所以,我想过滤我的通知合并在主线程MOC只是那些变化来自后台操作MOC。
获取/维护对后台操作MOC的引用的最干净的方法是什么,以便我有一些东西可以插入addObserver方法并且通知被正确过滤?我可以想到很多涉及到大量耦合的方法,但它们看起来都像是一个hack。
有什么建议或想法吗?其他人是如何处理的呢?
在我的应用程序中是这样工作的:
// should be executed on a background thread
- (void)saveWorkerContext {
if ([_workerContext hasChanges]) {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(workerContextDidSave:)
name:NSManagedObjectContextDidSaveNotification object:_workerContext];
NSError *error;
if (![_workerContext save:&error]) {
NSAssert(NO, @"Error on save: %@", error);
}
[nc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:_workerContext];
}
}
- (void)workerContextDidSave:(NSNotification *)notification {
if (_mainContext) {
[_mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification waitUntilDone:NO];
}
}
—修改答案—
使用NSFectchedResultsController似乎是你最好的选择。当它的MOC效果发生变化时它会通知它的委托。这消除了视图控制器从后台MOC了解或直接观察事件的需要。
这是我在NSOperation worker进程中使用的模式。
将后台MOC存储在maxConcurrentOperationCount为1的NSOperationQueue子类中。这确保了操作将连续发生。
- 子类NSOperationQueue
- 为背景MOC添加属性
- 实现NSOperationQueue的MOC getter,从Persistent store中惰性地创建后台MOC,并注册负责合并上下文和后台MOC的类(通常是AppDelegate或singleton)
- 取消类的观测值并清除dealc 中的背景MOC
在添加操作之前,从队列的后台MOC属性中为它们提供后台MOC。当预定时,您的操作将与后台MOC一起执行工作并保存。
当观察类收到did save通知时执行合并。合并后,每个使用前景MOC获取结果的控制器将在任何更改对结果产生影响时通知它的委托。这包括添加或删除背景MOC合并。
我不确定我完全理解你的问题:如果你只有一个后台线程与一个特定的MOC相关联,你想跟踪,那么没有什么特别要做的:使用属性来维护对MOC的引用。您可以像往常一样处理它,如下面的代码片段所示。
// create a new MOC
self.backgroundMOC = ...;
// register to receive notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selselector:@selector(contextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:self.backgroundMOC];
// pass backgroundMOC to your background thread
// and handle notifications here
- (void)contextDidSave:(NSNotification *)notification
{
NSManagedObjectContext *MOC = (NSManagedObjectContext *) [notification object];
if([MOC isEqual:self.backgroundMOC])
[managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}
如果您不想在持有上下文的线程/操作之间进行任何通信,那么识别生成通知的上下文是否属于您的唯一方法是检查其持久存储url。
只有你的上下文有你的商店url。API url将具有系统存储或内存存储。
当然,通常情况下,您确实在进程之间进行通信,并且可以仅传递用于标识目的的对象引用。