2

我有一个基于文档的核心数据应用程序(在 Mac OS X 10.5 及更高版本上运行),我试图NSManagedObjectContext在主线程上使用两个 's。我想将次要上下文中所做的更改合并到我的主要(主要)上下文中。此外,我希望从辅助上下文中合并的更改是可撤消的,并导致文档被标记为“脏”。我想我的问题类似于“撤消在主线程之外执行的核心数据插入”但是,ATM,我没有使用不同的线程。

我一直在观察NSManagedObjectContextDidSaveNotification(调用时从第二个上下文发送-[self.secondaryContext save:])是这样的:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(mocDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:self.secondaryContext];

-mocDidSave:观察者调用的方法中,我尝试在主要上下文上使用-[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:]将次要上下文中的更改合并到主要上下文中:

- (void)mocDidSave:(NSNotification *)notification
{
    [self.primaryContext mergeChangesFromContextDidSaveNotification:notification];
}

但是,虽然插入的对象很容易出现在我的数组控制器中,但文档没有标记为脏,并且isInserted新添加的托管对象的属性没有设置为 YES。插入(到主要上下文中)也是不可撤消的。

对任何插入的对象进行重新故障至少会将文档标记为脏,但插入仍然不可撤消:

- (void)mocDidSave:(NSNotification *)notification
{
    [self.primaryContext mergeChangesFromContextDidSaveNotification:notification];

    for (NSManagedObject *insertedObject in [[notification userInfo] objectForKey:NSInsertedObjectsKey]) {
        [self.primaryContext refreshObject:[self.primaryContext existingObjectWithID:[insertedObject objectID] error:NULL] mergeChanges:NO];
    }
}

Wrt -mocDidSave:,我通过自定义实现获得了更好的结果:

- (void)mocDidSave:(NSNotification *)notification
{
    NSDictionary *userInfo = [notification userInfo];

    NSSet *insertedObjects = [userInfo objectForKey:NSInsertedObjectsKey];
    if ([insertedObjects count]) {
        NSMutableArray *newObjects = [NSMutableArray array];
        NSManagedObject *newObject = nil;
        for (NSManagedObject *insertedObject in insertedObjects) {
            newObject = [self.primaryContext existingObjectWithID:[insertedObject objectID] error:NULL];
            if (newObject) {
                [self.primaryContext insertObject:newObject];
                [newObjects addObject:newObject];
            }
        }

        [self.primaryContext processPendingChanges];

        for (NSManagedObject *newObject in newObjects) {
            [self.primaryContext refreshObject:newObject mergeChanges:NO];
        }
    }

    NSSet *updatedObjects = [userInfo objectForKey:NSUpdatedObjectsKey];
    if ([updatedObjects count]) {
        NSManagedObject *staleObject = nil;
        for (NSManagedObject *updatedObject in updatedObjects) {
            staleObject = [self.primaryContext objectRegisteredForID:[updatedObject objectID]];
            if (staleObject) {
                [self.primaryContext refreshObject:staleObject mergeChanges:NO];
            }
        }
    }

    NSSet *deletedObjects = [userInfo objectForKey:NSDeletedObjectsKey];
    if ([deletedObjects count]) {
        NSManagedObject *staleObject = nil;
        for (NSManagedObject *deletedObject in deletedObjects) {
            staleObject = [self.primaryContext objectRegisteredForID:[deletedObject objectID]];
            if (staleObject) {
                [self.primaryContext deleteObject:staleObject];
            }
        }

        [self.primaryContext processPendingChanges];
    }
}

这会导致我的数组控制器得到更新,文档被标记为脏,并且插入和删除是不可撤销的。但是,我仍然遇到无法撤消的更新问题。我是否应该手动循环遍历所有 updatedObjects 并用于-[NSManagedObject changedValues]重新应用主上下文中的更改?

当然,这种自定义实现会在主上下文中从辅助上下文中复制大量工作。是否有任何其他/更好的方法可以在两个上下文之间进行合并,同时将合并保持为可撤消的步骤?

4

1 回答 1

1

如果您不使用单独的线程,那么您实际上不需要单独的上下文。在同一个线程上使用两个上下文会增加复杂性而不会获得任何东西。如果您不确定是否会使用线程,那么我强烈建议您只使用一个上下文。过早的优化是万恶之源。

保存重置撤消管理器,因此您不能使用它NSManagedObjectContextDidSaveNotification来执行任何可以撤消的操作。正如您发现的那样,您可以欺骗应用程序认为文档是脏的,但您不能强制撤消管理器记住上次保存的时间。

要获得无限撤消,唯一的方法是在幕后保存文档的多个版本。IIRC,您还可以序列化撤消管理器,以便可以将其写入文件并重新加载以回溯。

于 2011-07-01T16:32:57.820 回答