Multithreading 确保在收到NSManagedObjectContextObjectsIDChangeNotification之后而不是之前接收到从另一个线程发送到对象的消息

Multithreading 确保在收到NSManagedObjectContextObjectsIDChangeNotification之后而不是之前接收到从另一个线程发送到对象的消息,multithreading,grand-central-dispatch,nsmanagedobjectcontext,nsnotificationcenter,Multithreading,Grand Central Dispatch,Nsmanagedobjectcontext,Nsnotificationcenter,我的应用程序有一个典型的核心数据后端,包含父对象和子对象 父级NSManagedObjectContext,moc1,具有NSMainQueueConcurrencyType 子NSManagedObjectContext,moc2,具有NSPrivateQueueConcurrencyType 我还有一个对象X,它观察moc1的nsmanagedObjectContextObjectsIDChangeNotification。此通知必须到达主线程 问题:假设对后台队列上的moc2进行了更改,然

我的应用程序有一个典型的核心数据后端,包含父对象和子对象

父级
NSManagedObjectContext
moc1,具有
NSMainQueueConcurrencyType

NSManagedObjectContext
moc2,具有
NSPrivateQueueConcurrencyType

我还有一个对象X,它观察moc1
nsmanagedObjectContextObjectsIDChangeNotification
。此通知必须到达主线程

问题:假设对后台队列上的moc2进行了更改,然后调用
[moc2 save:://code>。然后,如何在主线程上向对象X发送消息,并确保在收到
NSManagedObjectContextObjectsDidChangeNotification
之后而不是之前收到该消息?致电:

[moc2 save:NULL];  // causes X to get NSManagedObjectContextObjectsDidChangeNotification for moc1...eventually
dispatch_async(dispatch_get_main_queue(), ^{
    [X iHopeYouGetThisAfterYouGotTheNotification];
};

即使您根据经验观察到这样一个块是在通知之后执行的,依赖它也将假定未记录的实现细节。可以安全地依赖的是,NSNotificationCenter同步发送其通知(以下讨论的特定情况除外),因此通过添加另一个观察者并从那里调度块,您可以更安全

您可以这样做(假设为圆弧):

由于该通知将在发布队列上同步传递,因此您可以确信,
-ihopeyougetthis after you获得通知后将发生通知
,而不管发布通知的线程是什么

请注意,如果
X
以异步方式接收通知(例如,通过使用
-addObserverForName:object:queue:usingBlock:
订阅通知并通过
[NSOperationQueue mainQueue]
),则这将无法保证工作,但这似乎不太可能(而且是可以避免的)安排

__block id token = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object: moc1 queue: nil usingBlock:^(NSNotification *note) {
    if (token)
    {
        id copyOfToken = token; // so it'll be const-copied into the next block, despite token being nilled out
        dispatch_async(dispatch_get_main_queue(), ^{
            [X iHopeYouGetThisAfterYouGotTheNotification];
            [[NSNotificationCenter defaultCenter] removeObserver: copyOfToken];
        });
        token = nil;
    }
}];