3

使用两个托管对象上下文时,我在单个上下文中遇到了同一实体的重复对象的问题。

考虑以下代码:

[childMOC performBlockAndWait:^{

    // CREATE PERSON IN CHILD MOC
    Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" 
                                                   inManagedObjectContext:childMOC];

    person.name = @"Ben";

    // SAVE CHILD MOC TO PUSH CHANGES TO MAIN MOC
    [childMOC save:nil];

    NSManagedObjectID *personID = person.objectID;

    [mainMOC performBlockAndWait:^{
        // SAVE MAIN MOC TO PERSIST THE PERSON AND REPLACE ID TO PERMANENT
        [mainMOC save:nil];

        // GET THE PERSON IN THE MAIN MOC
        Person *personInMainContext = (Person*)[mainMOC objectWithID:personID];

        // GET THE PERSON'S NEW PERMANENT ID
        NSManagedObjectID *personIdAfterSaveToPersistentStore = personInMainContext.objectID;

        [childMOC performBlockAndWait:^{

            // GET THE PERSON IN THE CHILD MOC WITH ITS NEW PERMANENT ID
            // (this is common when sending the id from mainMOC to childMOC)
            Person *samePersonFetchedFresh = (Person*)[childMOC objectWithID:personIdAfterSaveToPersistentStore];

            // THE PERSON OBJECTS SHOULD BE EXACTLY THE SAME BECAUSE THE MOC GUARANTEES UNIQUING
            samePersonFetchedFresh.name = @"Jerry";
            NSLog(@"%@ & %@", person.name, samePersonFetchedFresh.name);

            // OUTPUT: Ben & Jerry
            // NOT THE SAME?!
        }];
    }];
}];

这意味着在子 MOC 中创建的对象在保存在主 MOC/持久存储中时会失去其独特的能力。

谁能解释为什么 uniquing 在这种情况下不起作用?

4

3 回答 3

0

在记录其名称之前尝试刷新您的人。我认为唯一有效但缓存失效可能不会。

于 2012-06-28T12:29:28.253 回答
0

在某个地方,您应该收听主上下文NSManagedObjectContextDidSaveNotification,并使用 将更改传播到子上下文mergeChangesFromContextDidSaveNotification

如果完全合并不适合您的需要,您还可以使用 .单独更新每个实体refreshObject:mergeChanges:

如果您不想处理最新的实例和旧副本,则必须以一种或另一种方式传播更改。

这不是自动完成的,这是好的,因为操作可能非常繁重。对于相关上下文,您必须在适当的时候处理合并。例如,如果您使用一些 JSON 服务填充数据库,您将使用上下文向数据库添加实体,并且您希望在数据一致时更新 UI,而不是每次将内容保存到主要上下文,也许还有磁盘。同样,该上下文肯定对 UI 中所做的更改不感兴趣,然后保存到主上下文/磁盘。因此,该过程不是自动的。

于 2012-06-28T13:06:54.943 回答
0

我的解决方案是:

1)使用背景MOC作为父MOC,主MOC作为子MOC。作为奖励,我不需要保存主 MOC 来获得永久 ID。

[DC.backgroundMOC performBlock:^{
    // Add, save and update managed objects
    [DC saveContext]; // The changes is being pushed to the main context
}];

2) 使用 NSManagedObjectContextDidSaveNotification 使主 MOC 保持最新(主 MOC 正在更新 UI)

- (void) backgroundMOCSaved:(NSNotification*)notification {
    [mainMOC performBlock:^{
        [mainMOC mergeChangesFromContextDidSaveNotification:notification];
    }];
}
于 2012-07-29T20:28:58.930 回答