应用程序设计:处理具有背景上下文的核心数据;合并由MOC过滤的通知

时间:2011-05-02 17:33:17

标签: iphone ios core-data nsmanagedobjectcontext

我有一个应用程序设计问题,我希望有人可以提供帮助。

让我们进行一个非常简单的设置:用于显示来自服务器的新闻项的核心数据应用程序。

  • 主线程/ UI具有托管对象上下文,所有视图控制器都使用该上下文来显示数据。

  • NSOperation在后台运行,在同一个持久存储上检查服务器及其自己的上下文。

我想合并后台上下文中的更改,因此我使用NSManagedObjectContextObjectsDidChangeNotification。

According to the Apple docs

  

多个系统框架在内部使用Core Data。如果您注册从所有上下文接收这些通知(通过将nil作为object参数传递给addObserver ...方法),那么您可能会收到难以处理的意外通知。

所以,我想过滤我在主线程MOC中合并的通知,只是来自后台操作MOC的那些更改。

获取/维护对后台操作MOC的引用的最简洁方法是什么,以便我可以插入addObserver方法并正确过滤通知?我可以想到很多涉及大量耦合的方法,但它们看起来都像是黑客。

有任何建议或想法吗?别人怎么处理这个?

4 个答案:

答案 0 :(得分:4)

以下是我在应用中的工作原理:

// 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];
    }
}

答案 1 :(得分:2)

---修订答案---

使用NSFectchedResultsController似乎是您最好的选择。当它的MOC发生变化影响它的结果时,它会通知它的代表。这使得视图控制器无需了解或直接观察来自后台MOC的事件。

这是我在NSOperation工作流程中使用的模式。

将背景MOC存储在NSOperationQueue子类中,其maxConcurrentOperationCount为1.这可确保操作将以串行方式进行。

  • 子类NSOperationQueue
  • 为背景MOC添加属性
  • 实现NSOperationQueue的MOC getter,从Persistent商店懒洋洋地创建后台MOC,并注册负责合并上下文的类,后台MOC保存通知(通常是你的AppDelegate或单例)
  • 取消注册课程的观察结果并清理dealoc中的背景MOC

创建您的NSOperationQueue子类。

在添加操作之前,请使用队列的后台MOC属性中的后台MOC进行配置。安排后,您的操作将执行后台MOC工作并保存。

当观察类出现了保存通知时执行合并。合并后,每个使用前台MOC获取的结果控制器将在任何更改对其产生影响时通知其委托。这包括后台MOC合并中的添加或删除。

答案 2 :(得分:1)

我不确定我是否完全理解您的问题:如果您只有一个后台线程与您要跟踪的某个特定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];

}

答案 3 :(得分:1)

如果您不希望在保存上下文的线程/操作之间进行任何通信,那么识别生成通知的上下文是否属于您的唯一方法是检查其持久性存储URL。

只有您的上下文才会包含您的商店网址。 API URL将具有系统存储或内存存储。

通常,您当然会在进程之间进行通信,并且只需传递对象引用以进行标识。