NSManagedObjectContext:如何更新主上下文

时间:2011-12-14 21:07:29

标签: objective-c core-data nsmanagedobjectcontext

我有一个项目使用Core Data和默认的AppDelegate。我在我的代码中有以下线程,其中下载了我的NSManagedObject WSObject的图像。正如您将注意到的,我正在为此后台线程创建一个新的NSManagedObjectContext。我试图在网上阅读不同的文档和其他论坛主题,但是在我的对象保存在后台上下文中之后,我无法理解如何在AppDelegate中通知我的主要上下文。

- (void) downloadImageForObjectID:(NSManagedObjectID*)objectID {
    dispatch_queue_t imageDownloaderQueue = dispatch_queue_create("imagedownloader", NULL);
    dispatch_async(imageDownloaderQueue, ^{
        NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
        context.persistentStoreCoordinator = [(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator];
        context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;

        WSObject *item = (WSObject*)[context objectWithID:objectID];
        item.image.data = [item.image download];

        if ([context hasChanges]) {
            NSError *error = nil;
            [context save:&error];
        }
    });
    dispatch_release(imageDownloaderQueue);
}

有人可以告诉我要添加到此方法和AppDelegate以使其正常工作吗?据我所知,当我在后台线程中保存上下文时,会发送NSManagedObjectContextDidSaveNotification。我应该向AppDelegate添加什么代码来收听此通知以及收到通知后该怎么做?

EDIT1: 我已将观察者添加到后台线程中。

if ([context hasChanges]) {
    NSError *error = nil;


    NSManagedObjectContext *mainContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeHandler:) name:NSManagedObjectContextDidSaveNotification object:mainContext];

    [context save:&error];

    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:mainContext];
}

但AppDelegate中的mergeHandler永远不会被调用。

2 个答案:

答案 0 :(得分:12)

在使用您注册NSManagedObjectContextDidSaveNotification的AppDelegate类定义的通知处理程序中,您只需执行以下操作:

- (void)myManagedObjectContextDidSaveNotificationHander:(NSNotification *)notification
{
    // since we are in a background thread, we should merge our changes on the main
    // thread to get updates in `NSFetchedResultsController`, etc.
    [self.managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:NO];
}

假设self.managedObjectContext引用您的主NSManagedObjectContext,那就是它。

最简单的可能是在保存之前注册您的上下文,并在之后注销:

    if ([context hasChanges]) {
        NSError *error = nil;

       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myManagedObjectContextDidSaveNotificationHander:) name:NSManagedObjectContextDidSaveNotification object:context];

       [context save:&error];

       [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:context];
    }

答案 1 :(得分:4)

跟进gschandler,

你可以在appDelegate中找到

 [[NSNotificationCenter defaultCenter] addObserver:self 
                 selector:@selector(myManagedObjectContextDidSaveNotificationHander:) 
                     name:NSManagedObjectContextDidSaveNotification 
                   object:nil];

如果您将nil作为对象传递,则会收到您指定的name的所有通知,无论是哪个对象都已发送通知。

NSNotificationCenter Class Reference

  

notificationSender
  观察者想要接收其通知的对象;也就是说,只有此发件人发送的通知才会传递给观察者   如果您通过nil,通知中心不会使用通知的发件人来决定是否将其发送给观察者。


有了这个,您还应该收到主线程上下文的通知,因此您需要进行一些过滤以避免进入主线程保存的循环,获取通知发生更改并再次保存并获取通知等。