Objective c 如何确保在调用NSFetchedResultsController方法之前准备好UIManagedDocument?
我完全被这件事缠住了。我的基本问题是:Objective c 如何确保在调用NSFetchedResultsController方法之前准备好UIManagedDocument?,objective-c,ios,nsfetchedresultscontroller,uimanageddocument,Objective C,Ios,Nsfetchedresultscontroller,Uimanageddocument,我完全被这件事缠住了。我的基本问题是: - (NSFetchedResultsController *)fetchedResultsController 方法在尝试读取我的核心实体时崩溃,因为managedObjectContext/UIManagedDocument为nil。目前我认为这是因为我的UIManagedDocument尚未打开/准备就绪。因此,在过去的3个小时里,我一直在努力使我的委托方法在文档打开之前不会被激发 这是我用来获取文档的代码: if (!self.
- (NSFetchedResultsController *)fetchedResultsController
方法在尝试读取我的核心实体时崩溃,因为managedObjectContext/UIManagedDocument为nil。目前我认为这是因为我的UIManagedDocument尚未打开/准备就绪。因此,在过去的3个小时里,我一直在努力使我的委托方法在文档打开之前不会被激发
这是我用来获取文档的代码:
if (!self.document) {
[[CATManagedDocumentHandler sharedDocumentHandler] performWithDocument:^(UIManagedDocument *document) {
self.document = document;
}];
}
这在我的应用程序中的任何其他位置都可以正常工作,但对于我的tableView中的委托方法来说,打开过程似乎不够快
到目前为止,我已经查看了以下链接:
我尝试过:阻塞主线程直到收到NSNotification(在CATManagedDocumentHandler中设置)&阻塞主线程直到收到阻塞回调
这两种方法都不管用。我的应用程序冻结了。我想得不对吗?如何让委托方法等待文档打开/准备就绪?或者我应该采取不同的方法来解决这个问题
谢谢
卡尔。好的,当你的应用程序第一次启动时,我建议检查1。您的数据库存在(如果不存在,则分配init)和2。如果文档不存在(磁盘上),则关闭或打开 以下是如何做到这一点: 看起来您正在为数据库使用单例,因此,当您的第一个视图控制器出现时,请检查托管文档是否已被alloc初始化,以便在视图中显示:
if (!dataBase)
{
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:@"Your DB Name"];
self.dataBase=[[UIManagedDocument alloc]initWithFileUrl:url];
}
因此,现在如果数据库(UIManagedDocument)已被alloc初始化,这并不意味着实际的数据库文件已在磁盘上创建。您必须按如下方式检查它(您可以在数据库的setter或ViewDidLoad中执行此操作,但不要在另一个线程中执行,因为它不起作用)
因此,您在这里检查3个案例:不存在
if (![[NSFileManager defaultManager]fileExistsAtPath:[yourManagedDocumentFromSingleton.fileUrl path])
{
[[NSFileManager defaultManager]fileExistsAtPath:[yourManagedDocumentFromSingleton saveToUrl:[[NSFileManager defaultManager]fileExistsAtPath:[yourManagedDocumentFromSingleton.fileUrl forSaveOperation:UIDocumentSaveForCreating completionHandler:
^(BOOL success){ now you can use your uidocument and its managed object context}];
}
如果文件确实存在但已关闭:
else if (yourManagedDocumentFromSingleton.documentState==UIDocumentStateClosed)
{
[yourManagedDocumentFromSingleton openWithCompletionHandler:
^(BOOL success) {use your document here}];
}
最后,如果文档已经打开,只需使用它:
else if (yourManagedDocumentFromSingleton.documentState=UIDocumentStateNormal)
{
//do whatever with the document
}
需要提及的一件重要事情是UIDocument不是线程安全的。所以它必须在创建它的同一个线程中使用和检查(这里大概是主线程)。否则它将无法工作
我不知道视图控制器或singleton的确切结构,但是如果您按照这些步骤操作,它就会工作
另外,还要确保一旦您的文档启动并运行,并且您正在向其中添加或删除项目,在每次操作后保存它,以便更新NSFetchedResultsController。CoreData确实有自动保存功能,但我发现我必须手动保存才能正常工作。您可以使用(以前的方法)保存:
感谢您的回复和努力回复。我现在已设法打开并准备好我的文档。。。但奇怪的是,当我做取回请求时。。。我无法设置我的“entityName”。。。我以前从来没有这样过。。。它只是返回“executeFetchRequest:error:获取请求必须有一个实体”。从上面的链接中可以看出,我显然是在设置实体。。这也是存在的,并且是我的数据模型中的正确名称。。。。。。我刚刚在上一个屏幕上测试了实体的加载。它注销时没有问题..看起来您没有设置谓词。。。的确因此,除了sortDescriptor之外,还需要谓词。谓词告诉您要从查询的实体中提取哪些内容。创建fetch后,可以设置如下谓词:fetchRequest.predicate=[NSPredicate predicateWithFormat:@“yourEntityAttribute=%@”,someAttributeYouWant];谓词有多种格式,因此可以进行非常详细的查询。检查NSPredicate的文档
forSaveOperation:UIDocumentSaveForOverwriting