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