2011-02-07 90 views
5

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

一切工作正常,但它为将数据导入新文档的用户呈现了一个奇怪的工作流程。他们需要在导入之前保存一个空文档(否则-save:失败,因为该文档没有配置NSPersistentStoreCoordinator的URL)。除了某种“新文档设置”向导之外,我没有看到任何解决方法确保-writeToURL:ofType:forSaveOperation:originalContentsURL:error:在导入之前被调用。

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

我已经阅读了核心数据编程指南和Marcus Zarra的书,但我仍然对这个框架的这方面不熟悉。希望我忽略了一些事情:如果没有,我会使我的应用适应这些限制(Core Data的好处远远超过这些用户界面限制。)

感谢您的时间!

-

基于以下彼得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 
    } 
} 

然后,在保存时选择文件后面板,临时持久存储被迁移到一个SQLite储存在选定的URL:

- (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]; 
} 
+1

就像你在Mac上一样,你不能在内存存储中使用内存,然后在准备好时切换上下文以使用基于文件的存储?上面的方法也可以解决撤销问题,因为如果需要的话,你可以放弃整个上下文堆栈。似乎我在写这篇文章的时候大家写的都一样:) – Jonathan 2011-02-07 19:48:59

回答

5

我是没有人的核心数据专家,但从我可以从文档中知道的内容开始,您需要先从内存存储开始,直到用户(在他们自己的时间)保存文档。然后,发送协调者a migratePersistentStore:toURL:options:withType:error: message以从内存中存储转换为新的真正持久存储。请参阅该文档以获取一些重要细节(特别是关于您迁移的商店的命运)。

+0

谢谢彼得!迁移是缺少的难题 - 我已经更新了我的帖子。 – chockenberry 2011-02-07 22:32:46

2

我在工作流程的第一个念头/保存的部分将是,如果persiste nt store尚未为文档创建,以创建临时内存中存储,以便导入的数据将保存到该存储中(尽管文档/窗口仍将被标记为脏)。然后,一旦用户将文档保存为真实的文件,您将重新配置协调器以删除内存中的存储并将其替换为磁盘上的存储,因此所有进一步的保存都将存入磁盘。

0

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

+0

好的解决方案,但是就像Daniel,Peter&Brian说的那样,简单地创建一个内存存储就更简单了,更不用说更快了。然而,如果我们谈论一个非常大的数据集,这将是一个替代方案。 – Jonathan 2011-02-07 19:52:44

2

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

可能更好的方法是在标准临时目录中创建磁盘上的永久性存储,并在用户单击以保存时将其移动到整个磁盘上。