如何忽略NSManagedObjectContextWillSaveNotification中mergeChangesFromContextDidSaveNotification的更改

时间:2016-03-01 21:02:05

标签: ios core-data nsmanagedobject nsmanagedobjectcontext

我正在使用私有托管对象上下文在持久性存储中创建一些新对象,然后在保存私有MOC之后,使用mergeChangesFromContextDidSaveNotification将它们合并到主MOC中。这样可以正常工作,并根据需要更新UI,并且NSManagedObjectContextWillSaveNotification不会在此处调用mainMOC

然后我使用用户界面对mainMOC进行了一些更改,然后收听NSManagedObjectContextWillSaveNotification。通知已发布,但它不仅包含我所做的编辑,还包含使用PrivateMOCmergeChangesFromContextDidSaveNotification合并的对象。

有没有办法在后续的mainContext通知中忽略从其他上下文合并到contextDidChange的更改?

以下是设置:

- (void) loadData {
   privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType];

   privateContext.persistentStoreCoordinator = self.mainContext.persistentStoreCoordinator;

   [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(contextWillSave:)
                                             name:NSManagedObjectContextWillSaveNotification
                                           object: self.mainContext];

   NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:record.recordType inManagedObjectContext: self.privateContext];

   // fill in object

   if ([self.privateContext hasChanges]) {
       [self savePrivateContextAndMergeWithMainContext: self.privateContext];
   }
}

- (void) savePrivateContextAndMergeWithMainContext: (NSManagedObjectContext *) privateContext {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(privateContextDidChange:) name:NSManagedObjectContextDidSaveNotification object:privateContext];
    __block NSError *error = nil;
    [privateContext performBlockAndWait:^{
        NSLog(@"PrivateContext saved");
        [privateContext save:&error];
    }];


    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:privateContext];

    if (error) {
        NSLog(@"error = %@", error);
    }
}

- (void) privateContextDidChange: (NSNotification *) notification{

    [self.mainContext performBlockAndWait:^{
        NSLog(@"merged into mainContext");
        [self.mainContext mergeChangesFromContextDidSaveNotification:notification];
    }];
}

这样可以正常工作并保存私有上下文并合并到mainContext不会触发contextWillSave通知。但是,在从UI(在主MOC上)编辑数据时,会触发通知并包含先前使用私有MOC保存的数据。

希望很清楚。如果我应该包含其他任何内容,请告诉我。

- 更新 -

似乎问题在于专门从私有上下文中删除对象。从私有上下文中删除并在主MOC上调用mergeChangesFromContextDidSaveNotification后,mainMoc的deletedObjects集仍然显示已删除的对象。私有上下文中的插入或更新不会发生这种情况。这记录在哪里?什么是解决方法?

2 个答案:

答案 0 :(得分:2)

像这样修改privateContextDidChange ......

- (void) privateContextDidChange: (NSNotification *) notification{
    if (notification.object == PrivateMOC) {
        [self.mainContext performBlockAndWait:^{
            NSLog(@"merged into mainContext");
            [self.mainContext mergeChangesFromContextDidSaveNotification:notification];
        }];
    }
}

...其中PrivateMOC是对私有托管对象上下文的引用?

答案 1 :(得分:1)

核心数据已存在多年,并且在此期间并发模型已经发展。

"线程限制"并且"锁定"并发模型使用通知来在上下文之间传递更改。保存上下文时,将广播包含更改信息的通知。该信息可用于将来自一个上下文的更改合并到其他上下文中。这从未特别好地扩展,并且通常是应用程序的主要痛点。 "锁定"和#34;线程限制"模特已经淘汰了好几年了。

当"队列限制"介绍了"嵌套上下文的概念"随之而来。上下文可以具有父上下文,并且当保存子上下文时,这些更改将自动传递给父级(并且不再进一步)。这是在使用队列限制时在上下文之间传递更改的推荐方法。

建议不要将mergeChangesFromContextDidSaveNotification:NSPrivateQueueConcurrencyType背景一起使用。

核心数据代表您执行大量内部簿记和更改跟踪。通常在保存操作期间聚合和合并信息 - 这是processPendingChanges操作的一部分。当在performBlockAndWait:内执行保存操作时,这可能不会发生,或者可能不会完成 - 这会导致更改(以及任何更改通知)不完整或根本不发生。 performBlockAndWait:是可重入的,与processPendingChanges进程不兼容。使用performBlock:代替将导致更一致的行为。

如果您使用嵌套的上下文来传达更改而不是通知,那么您在问题中描述的问题将会得到解决。