【问题标题】:Core Data and NSOperation核心数据和 NSOperation
【发布时间】:2011-02-07 19:36:03
【问题描述】:

我目前正在使用NSPersistentDocument 子类,它使用NSOperation 在后台导入数据。根据文档,我在保存后台任务并使用-mergeChangesFromContextDidSaveNotification: 将通知传播到主线程中的NSManagedObjectContext 后观察NSManagedObjectContextDidSaveNotification

一切正常,但是对于将数据导入新文档的用户来说,它呈现出一个奇怪的工作流程。他们需要在导入之前保存一个空文档(否则 -save: 会失败,因为该文档没有为 NSPersistentStoreCoordinator 配置 URL。)除了某种“新文档设置”向导,确保在导入之前调用 -writeToURL:ofType:forSaveOperation:originalContentsURL:error:

此外,后台的导入任务似乎排除了在主线程上使用NSUndoManager。 (我假设跨线程共享托管对象上下文的撤消管理器是不安全的。)从用户的角度来看,没有办法撤消导入期间创建的所有新对象。

我已经阅读了 Core Data Programming Guide 和 Marcus Zarra 的书,但我对框架的这方面仍然很陌生。希望我忽略了一些事情:如果没有,我会让我的应用适应这些限制(Core Data 的好处远远超过这些用户界面限制。)

感谢您的宝贵时间!

--

根据下面 Peter Hosey 的建议,我添加了以下代码以在导入之前创建一个临时持久存储:

NSPersistentStoreCoordinator *persistentStoreCoordinator = [self.managedObjectContext persistentStoreCoordinator];
if ([[persistentStoreCoordinator persistentStores] count] == 0) {
    // create an in-memory store to use temporarily
    NSError *error;
    NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&error];
    if (! persistentStore) {
        NSLog(@"error = %@", error); // TODO: better error handling
    }
}

然后,在保存面板中选择文件后,临时持久存储将迁移到所选 URL 处的 SQLite 存储:

- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError **)error
{
    NSPersistentStoreCoordinator *persistentStoreCoordinator = [self.managedObjectContext persistentStoreCoordinator];
    for (NSPersistentStore *persistentStore in [persistentStoreCoordinator persistentStores]) {
        if (persistentStore.type == NSInMemoryStoreType) {
            // migrate the in-memory store to a SQLite store
            NSError *error;
            NSPersistentStore *newPersistentStore = [persistentStoreCoordinator migratePersistentStore:persistentStore toURL:absoluteURL options:nil withType:NSSQLiteStoreType error:&error];
            if (! newPersistentStore) {
                NSLog(@"error = %@", error); // TODO: better error handling
            }
        }
    }

    return [super writeToURL:absoluteURL ofType:typeName forSaveOperation:saveOperation originalContentsURL:absoluteOriginalContentsURL error:error];
}

【问题讨论】:

  • 作为你的mac,你不能使用内存存储,然后在你准备好时切换上下文以使用基于文件的存储吗?以上也可以解决撤消的问题,因为如果需要,您可以省去整个上下文堆栈。似乎在我写这篇文章的时候每个人都在写同样的东西:)

标签: core-data nsoperation nsundomanager


【解决方案1】:

我不是任何人的核心数据专家,但从我从文档中可以看出,您需要从内存存储开始,直到用户(在他们自己的时间)保存文档。然后,发送协调器a migratePersistentStore:toURL:options:withType:error: message 从内存存储切换到新的真正持久存储。请参阅该文档了解一些重要细节(尤其是关于您迁移的商店的命运)。

【讨论】:

  • 谢谢彼得!迁移是缺失的一块拼图——我已经更新了我上面的帖子。
【解决方案2】:

我对工作流/保存部分的第一个想法是,如果尚未为文档创建持久存储,则创建一个临时内存存储,以便将导入的数据保存到该存储(尽管文档/窗口仍会被标记为脏)。然后,一旦用户真正保存了文档,您将重新配置协调器以删除内存存储并将其替换为磁盘存储,因此所有进一步的保存都将转到磁盘。

【讨论】:

    【解决方案3】:

    我不是 100% 熟悉 Mac 的东西,但我相信你可以在用户保存之前使用内存中的持久存储,然后在该操作之后添加 sql/plist 存储。

    更好的方法是在标准临时目录中创建磁盘上的持久存储,并在用户单击保存时将其移动。

    【讨论】:

      【解决方案4】:

      您在设置协调器时是否尝试过设置临时文件 URL? 您应该能够撤消 -mergeChangesFromContextDidSaveNotification: 在主线程上。无需在后台线程上为 MOC 注册撤消管理器。

      【讨论】:

      • 很好的解决方案,但是就像 Daniel、Peter 和 Brian 所说的那样,简单地创建一个内存存储就更简洁了,更不用说更快了。但是,如果我们谈论的是一个非常大的数据集,这将是一个替代方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      • 2010-12-04
      相关资源
      最近更新 更多