Сохранение/объединение NSManagedObjectContext в нескольких потоках через проблему с центром уведомлений

Это больше вопрос, почему это работает, и это не вопрос...

Я использую CoreData в нескольких потоках. У меня есть два потока, созданных из основных потоков, и оба они выполняют аналогичный вызов:

    id observerObject = [notificationCenter addObserverForName:NSManagedObjectContextDidSaveNotification 
                                                        object:secondManagedObjectContext 
                                                         queue:nil 
                                                    usingBlock:^(NSNotification *saveNotification) {
                                                        dispatch_async(dispatch_get_main_queue(), ^{
                                                            [mainThreadManagedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
                                                        });
                                                    }];
    [secondManagedObjectContext save:nil];


    [notificationCenter removeObserver:observerObject
                                  name:NSManagedObjectContextDidSaveNotification 
                                object:syncManagedObjectContext];

Кажется, это работает нормально, но раньше я делал это с центром уведомлений и имел некоторые проблемы:

    id observerObject = [notificationCenter addObserverForName:NSManagedObjectContextDidSaveNotification 
                                                        object:secondManagedObjectContext 
                                                         queue:[NSOperationQueue mainQueue]
                                                    usingBlock:^(NSNotification *saveNotification) {
                                                        [mainThreadManagedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
                                                    }];

Иногда это срабатывало, но в других случаях XCode останавливался при запуске и сбрасывал зеленую точку останова при вызове и просто перечислял поток и его номер, но без ошибки. (Примечание: эта проблема возникает только в том случае, если я создал два или более потока).

Виновником, по-видимому, является: [NSOperationQueue mainQueue], но я не могу понять, почему поток приостанавливается. Я смог нажать "Продолжить" в отладчике и просто двигаться дальше... но я не понимаю, почему он так работает.

Я предполагаю, что делаю что-то не так, и беспокоюсь, что мой новый способ может быть просто взломом.

Спасибо за помощь!


person Derek    schedule 04.05.2011    source источник


Ответы (3)


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

person TechZen    schedule 05.05.2011

Не уверен, поможет ли это, но если у вас есть ноль для очереди, попробуйте использовать общую очередь. Взгляните на шаблон дизайна администратора в документации Apple.

 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
person Arvin    schedule 07.12.2011

Слияние в вашем первом примере кода правильно отправляется в основной поток, который, скорее всего, также является потоком, в котором был создан moc.

Во втором примере слияние будет выполняться в фоновом потоке, если уведомление было выдано в потоке bg (обратные вызовы уведомлений всегда вызываются в том же потоке, в котором публикуется уведомление).

Кстати, вместо использования основной очереди я бы предпочел использовать собственный метод performBlock: NSManagedObjectContext (>= iOS 5). На iOS5 с ARC этот код сводится к следующему:

__weak typeof(self) weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    [weakSelf.moc performBlock:^{
        [weakSelf.moc mergeChangesFromContextDidSaveNotification:note];
    }];
}];
person manmal    schedule 15.10.2012