我正在为iPhone构建一个标签栏应用程序,并且正在将Core Data
与两个UIManagedDocument
一起使用。在第一个选项卡中,我将数据写入数据库,在第二个选项卡中,使用UITableView
将它们读入UIFetchedResultsController
。
在应用程序启动时,如果我先写入数据,然后再读取结果,则可以正常工作。结果立即显示在第二个选项卡中。但是,如果我先读取一些数据,然后再向数据库中写入一些数据,则结果将显示在第二个选项卡中,并且会有相当大的延迟(将近1分钟)。如果两个UIManagedObjectContext
或两个UIManagedDocument
之间存在任何同步问题,在第一种情况下它将如何工作?并且,对此延迟有什么解决方案吗?
最佳答案
您可以确保UIManagedDocument是最新的方法是确保正确保存更改。根据上面显示的信息,我不太确定如何管理文档或managedObjectContexts。有太多因素可能会影响这一点,从而无法为您提供100%的具体答案。
因此,不知道您的代码是什么样子,也不知道您如何管理上下文,我唯一能做的就是为您提供我在自己的项目中使用的内容。这可能对您有所帮助,也可能无济于事,但是在UIManagedDocument
处理核心数据方面,它对我的帮助超过了一次。
关于上下文:
我使用单例来管理UIManagedDocument。之所以这样做,是因为我不想处理您在上面所说的内容-具有多个managedObjectContext。当您开始处理多个上下文时,您会遇到以下问题:除非正确管理所有上下文,否则数据将不一致。如果您保存其中一个但不更新另一个,则您的数据可能会变得不同步。您还必须确保每个上下文都在属性thread
上起作用-Apple文档是了解为什么广告如此重要的重要资源。
不过,要点是,这是使用UIManagedDocument的最大问题之一,并没有像使用纯核心数据和使用SQL持久存储那样糟糕。我发现的主要原因是因为UIManagedDocument实际上是如何保存到其UIDocument存储的。关于何时保存它是非常不可预测的。这使您知道UIManagedDocument何时会真正持久保存,并使您的数据处于黑暗中。您最终不得不做各种愚蠢的事情,只是要确保它总是随时可用。
考虑到我有一个信念(很多人也许是对的,相信这是一个无知的信念),认为处理核心数据很困难,并且UIManagedDocument使得它比根本不使用它更容易。话虽这么说,但是当我使用像UIManagedDocument这样简单的东西变得复杂时,我不喜欢它-所以我使用了一件事始终保持简单,那就是单个UIManagedDocument的单例共享实例,因此我只有1个ManagedObjectContext可以使用。
关于保存:
每当我对模型进行任何重大更改(Create,Update,Delete,Edit)时,我总是确保调用[document updateChangeCount:UIDocumentChangeDone];
这样做,因为在使用UIManagedDocument时我不使用“撤消管理器”(NSUndoManager)。仅仅是因为我还不需要,再加上因为我讨厌您要处理的所有“变通”垃圾。
仅在主线程上工作:
每当我对UIManagedDocument或Core Data执行任何操作时,我始终确保其在主线程上。我想我已经讲过一次,但是我会再说一遍:在线程中工作在您需要时很有帮助,而且在您实际了解线程时也很有用。我喜欢在线程中工作,但这要付出复杂性的代价,这使我在涉及核心数据时不想在其中工作。在这种情况下,我倾向于严格地保留在主线程上,因为这使事情变得简单和容易(对我而言)。
保存文件
当我绝对需要确保UIManagedDocument已“保存”(写入磁盘)时,我有两种编写和使用的方法,对我来说总是可以使用它们:saveDocument
和forceSaveDocument
。
第一个(saveDocument)仅检查上下文的更改。如果有,则检查是否有任何新插入的对象。找到insertedObjects时,它将获取这些项目的权限ID。您可以认为这是确保核心数据模型是最新的,并且托管上下文处于安全状态的一种好方法,这样,当实际保存文档时,便可以将所有内容保存在该状态下。它必须存在(您的ID已实现,您的上下文很整洁,一旦完成所有工作,您要保存的内容就代表了模型的状态)。
它的大哥forceSaveDocument
实际上首先呼叫saveDocument
。再次,以确保您的实际模型/上下文已保存且正确。如果返回成功(是),则它将实际进行保存并通过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年)。我敢肯定,比起我/我,聪明的人/男将更好,但是这些都是我所使用的。我从他们那里得到的好处是,这使我不必担心管理数据,并给我更大的自由来处理其他所有事情:
使用单例来管理我的
UIManagedDocument
,直到绝对需要多个线程为止-然后迁移以开始使用多个上下文(我从来不需要这样做-但是我再次尝试使事情变得简单)对模型进行任何更改时,请始终致电
updateChangeCount:UIDocumentChangeDone
。它的重量很轻,几乎没有影响。如果有的话,这将有助于确保您的文档保持最新状态,并且永远不会与数据太不同步。除非确实需要,否则不要使用撤消管理器(我尚未需要)
仅在绝对必要时才少量使用save / ForceSave(删除是使用它的一个很好的理由。或者如果您在一个视图控制器上创建了一个新项目,而在下一个视图控制器上需要它,但又不能等待核心数据和要同步的文档-有点像把它踢在屁股上,然后说:“我反对您随时保存-现在保存,大声笑。。)
最后的想法
以上都是我自己的信念和理解。这些来自大量的研究,阅读,在想要做正确的事情的同时,要使事情变得简单,这是一个痛苦。任何人都可以编写一个复杂的解决方案-但我认为基本问题始终存在:您是否真的需要复杂性,还是只是需要它才能起作用,以便您可以专注于更复杂的问题?
我敢肯定,以上内容比您可能想要的要多,甚至可能会添加比您更多的问题。如果您需要一些链接和资源,请告诉我,我会尽力将它们联系在一起。
无论哪种方式,希望对您有所帮助。