多个UIManagedDocument用于读写

我正在为iPhone构build一个标签栏应用程序,我正在使用两个UIManagedDocumentCore Data 。 在第一个选项卡中,我将数据写入数据库,然后在第二个选项卡中使用UIFetchedResultsController它们读入UITableView

在应用程序开始时,如果我先写入数据,然后再读取结果,它工作正常。 结果立即显示在第二个选项卡中。 但是,如果我先读取一些数据,然后如果我写入数据库的东西,结果出现在第二个选项卡上,相当大的延迟(差不多1分钟)。 如果在两个UIManagedObjectContext或两个UIManagedDocument之间是否存在同步问题,它在第一个条件中是如何工作的? 而且,有没有解决这个延迟?

您可以确保您的UIManagedDocument是最新的方式是确保您正确地保存您的更改。 鉴于上面显示的信息,我不确定如何pipe理文档或managedObjectContext。 有太多的因素可能会影响这个能够给你一个100%的具体答案。

所以不知道你的代码是什么样的,不知道你是如何pipe理你的上下文的,我唯一能做的就是给你我自己的项目中使用的东西。 这可能帮助你,但它帮助了我 – 通过UIManagedDocument处理核心数据的次数多于一次。

当涉及到上下文:

我使用单例来pipe理UIManagedDocument。 我这样做是因为我不想处理上面提到的问题 – 拥有多个managedObjectContext。 当您开始处理多个上下文时,除非您正确pipe理所有上下文,否则数据将不一致。 如果您保存一个,但不更新另一个 – 那么您的数据可能会失去同步。 您还必须确保每个上下文都在属性thread上工作 – Apple Docs是理解这些问题的重要资源。

关键是,这是使用UIManagedDocument时遇到最大问题之一,并不像使用纯核心数据和使用SQL持久性存储时那样糟糕。 我发现的主要原因是因为UIManagedDocument实际上保存到它的UIDocument存储。 什么时候想要保存是非常不可预测的。 这使得知道你的UIManagedDocument何时会实际上持续下去,并且让你的数据在黑暗中被拍摄出来。 你不得不做各种愚蠢的事情,以确保它总是随时可用。

考虑到我有一个信念(很多人可能认为这是一个无知的信念),使用核心数据是困难的,而UIManagedDocument使得它更容易,如果你根本没有使用它。 这就是说,我不喜欢它在处理UIManagedDocument开始变得复杂的事情时 – 所以我使用了一直保持简单的东西,那就是单个UIManagedDocument的单例,共享实例我只有1个managedObjectContext, 永远不得不使用。

当谈到节省:

每当我对模型进行任何重大改变(创build,更新,删除,编辑),我总是确保调用[document updateChangeCount:UIDocumentChangeDone]; 我这样做是因为在使用UIManagedDocument时使用“撤消pipe理器”(NSUndoManager)。 只是因为我还没有需要,加上因为我讨厌所有的“解决方法”垃圾,你必须做的。

只在主线上工作:

每当我对我的UIManagedDocument或Core Data做任何事情时,我总是确保它在主线程上。 我想我已经说了一次,但我会再说一遍:在线程中工作是有用的,当你需要它,而且当你真正了解线程总体。 我喜欢在线程中工作,但它的代价是复杂性,这使得我不想在核心数据中工作。 在这种情况下,我倾向于严格遵守主线程,因为这使得事情变得简单和简单(对我来说)。

保存文档

当我绝对需要确保UIManagedDocument被“保存”(写入磁盘)时,我有两个方法,我写和使用,总是随时可以调用: saveDocumentforceSaveDocument

第一个(saveDocument)只是检查上下文的变化。 如果有,则检查是否有新插入的对象。 当findInsertObjects时,它将获得这些项目的perm id。 您可以将此视为确保您的核心数据模型是最新的,并确保您的托pipe上下文处于安全状态的一种好方法,以便在实际保存文档时,将所有内容保存在状态(你的id已经实现了,你的上下文是干净的,当你完成所有的工作后,你要保存的内容就代表了你的模型的状态)。

其大哥, forceSaveDocument ,实际上首先调用saveDocument 。 同样,要确保你的实际模型/上下文被保存和正确。 如果返回成功(YES),则实际上将执行真正的保存,并通过saveToUrl将文档写入磁盘。

一些代码(希望它有帮助):

以下是这两种方法,以防止它的帮助:

 -(BOOL)saveDocument { NSManagedObjectContext *context = self.document.managedObjectContext; if(!context.hasChanges) return YES; NSSet *inserts = [context insertedObjects]; if([inserts count] > 0) { NSError *error = nil; if(![context obtainPermanentIDsForObjects:[inserts allObjects] error:&error] && error) { [self reportError:error]; return NO; } } return YES; } -(void)forceSaveDocument { if( [self saveDocument] ) { [self.document saveToURL:self.document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:self.onSaveBlock ? self.onSaveBlock : nil]; } } 

一般规则/准则

总的来说,这些是我遵循UIManagedDocument和Core Data的指导方针(并且已经为我工作了大约3年)。 我敢肯定有更好的比我更聪明的家伙/女孩,但这些都是我用的。 我从中得到的好处是,它使我不必担心pipe理数据,并给予我更多的自由来处理其他事情:

  • 使用单例pipe理我的UIManagedDocument 直到需要多个线程是绝对必要的 – 然后迁移到开始使用多个上下文(我从来没有需要这样做 – 但我再次尝试保持简单)
  • 当我对模型进行任何更改时, 总是调用updateChangeCount:UIDocumentChangeDone 。 它重量轻,影响不大。 如果有的话,这将有助于确保您的文档保持最新状态,永远不会与您的数据不同步。
  • 不要使用撤消pipe理器,除非你真的需要它(我还没有需要它)
  • 只使用save / ForceSave,并且只有在绝对必要时(删除才是使用它的好理由,或者如果你在一个视图控制器上创build一个新的项目,并且需要它在下一个,但是不能等待核心数据和文件同步 – 就像在屁股踢它,说:“我反对你保存时,只要你想 – 现在保存大声笑..)

最后的想法

以上所有都是我自己的信念和理解。 这些来自于大量的研究,阅读,并且在想要做正确的事情时会变得很痛苦,同时保持简单。 任何人都可以编写一个复杂的解决scheme – 但我认为最基本的问题是:你真的需要复杂性,还是只是需要它,才能专注于更复杂的问题?

我相信上面的方式比你想要的要多,甚至可能会增加比你更多的问题。 如果你需要一些链接和资源,让我知道,我会尽量把几个一起。

无论哪种方式,希望有所帮助。