NSManagedObjectContext: как обновить основной контекст - PullRequest
3 голосов
/ 15 декабря 2011

У меня есть проект, использующий базовые данные со стандартным 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];
}

Но mergeHandler в AppDelegate никогда не вызывается.

Ответы [ 2 ]

12 голосов
/ 15 декабря 2011

В вашем обработчике уведомлений, определенном с вашим классом AppDelegate, который вы зарегистрировали для NSManagedObjectContextDidSaveNotification, вам просто нужно сделать следующее:

- (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];
    }
4 голосов
/ 15 декабря 2011

Чтобы следить за gschandler,

в вашем appDelegate вы можете сделать так:

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

если вы передадите nil в качестве объекта, вы получите все уведомления для name что вы указали независимо от того, какой объект отправил его.

Ссылка на класс NSNotificationCenter

messagesSender
Объект, уведомления которого хочет получить наблюдательПолучать;то есть только уведомления, отправленные этим отправителем, доставляются наблюдателю.
Если вы передаете ноль, центр уведомлений не использует отправителя уведомления, чтобы решить, следует ли доставить его наблюдателю.


При этом вы также должны получать уведомления от контекста основного потока, поэтому вам нужно будет выполнить некоторую фильтрацию, чтобы избежать перехода в круг с сохранением основного потока, получением уведомления об изменении и повторным сохранениеми получать уведомления и т. д.

...