如何在调用 NSFetchedResultsController 方法之前确保 UIManagedDocument 准备就绪?

Posted

技术标签:

【中文标题】如何在调用 NSFetchedResultsController 方法之前确保 UIManagedDocument 准备就绪?【英文标题】:How to ensure UIManagedDocument is ready before NSFetchedResultsController method is called? 【发布时间】:2012-12-08 16:31:21 【问题描述】:

我完全坚持这个。我的基本问题是我的:

   - (NSFetchedResultsController *)fetchedResultsController

方法在尝试读取我的核心核心实体时崩溃,因为 managedObjectContext / UIManagedDocument 为 nil。目前我认为这是因为我的 UIManagedDocument 没有打开/准备好。因此,在过去的 3 个小时里,我一直在努力做到这一点,以便在文档打开之前不会触发我的委托方法。

这是我用来获取文档的代码:

      if (!self.document) 
    [[CATManagedDocumentHandler sharedDocumentHandler] performWithDocument:^(UIManagedDocument *document) 
        self.document = document;         
    ];
 

这在我的应用程序的任何其他地方都可以正常工作,但似乎打开过程对于我的 tableView 中的委托方法来说不够快。

到目前为止我看过的链接:

http://omegadelta.net/2011/05/10/how-to-wait-for-ios-methods-with-completion-blocks-to-finish/

Executing Code Block In Place Of @selector

About calling of dispatch_queue_t and dispatch_sync

Grand Central Dispatch (GCD) vs. performSelector - need a better explanation

GCD to perform task in main thread

iOS - how to be notified when a thread (using GCD) ends it's job

我尝试过:阻塞主线程直到我得到 NSNotification(在 CATManagedDocumentHandler 中设置)&阻塞主线程直到我得到一个阻塞回调。

这些都不起作用。我的应用程序只是冻结。我想错了吗?如何让委托方法等到我的文档打开/准备好?或者我应该采取不同的方法吗?

谢谢

卡尔。

【问题讨论】:

【参考方案1】:

好的,当您的应用程序第一次启动时,我建议检查 1. 您的数据库是否存在(如果不存在,则分配初始化它)和 2. 如果文档不存在(在磁盘上),则关闭或者是开放的。

你可以这样做:

看起来你正在为你的数据库使用单例,所以当你的第一个视图控制器出现时,检查托管文档是否已被分配,所以在 ViewWillAppear 中:

if (!dataBase)

        NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        url = [url URLByAppendingPathComponent:@"Your DB Name"];
        self.dataBase=[[UIManagedDocument alloc]initWithFileUrl:url];

所以现在如果数据库(UIManagedDocument)已经被分配,它仍然不意味着实际的数据库文件已经在磁盘上创建。您必须按如下方式检查它(您可以在数据库的 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 不是线程安全的。所以它必须在创建它的同一个线程中使用和检查(这里大概是主线程)。否则将无法正常工作。

我不知道您的视图控制器或单例的确切结构,但如果您按照这些步骤操作,它将起作用。

PS。还要确保一旦您的文档启动并运行并且您正在向其中添加或删除项目,请在每次操作后保存它,以便您的 NSFetchedResultsController 得到更新。 CoreData 确实有自动保存功能,但我发现我必须手动保存才能正常工作。您可以使用(从以前的方法)保存:

forSaveOperation:UIDocumentSaveForOverwriting

【讨论】:

感谢您的回复和努力回复。我现在已经设法让我的文档打开并准备好了......但奇怪的是,当我发出获取请求时......我无法设置我的“实体名称”......我以前从未有过这个......它即将到来返回 '​​executeFetchRequest:error: 获取请求必须有一个实体。' skydrive.live.com/… 正如您从上面的链接中看到的那样,我清楚地设置了一个实体.. 这也存在并且是我的数据模型中的正确名称... ... 并且只是提一下:我刚刚在前一个屏幕上测试了实体的加载。它没有问题地注销.. 看起来你没有设置谓词......确实。所以除了sortDescriptor之外你还需要谓词。谓词告诉您要从您查询的实体中提取哪些内容。创建 fetch 后,设置谓词如下: fetchRequest.predicate=[NSPredicate predicateWithFormat:@"yourEntityAttribute=%@", someAttributeYouWant];谓词有多种格式,因此您可以进行非常详细的查询。检查 NSPredicate 的文档

以上是关于如何在调用 NSFetchedResultsController 方法之前确保 UIManagedDocument 准备就绪?的主要内容,如果未能解决你的问题,请参考以下文章

react中如何在静态方法中调用静态属性

如何在C#中webservice调用方法总结

如何在网页中调用webservice?

如何在html中调用js代码

如何在CSS中调用公用css

如何在 HTML JavaScript 中调用 mfc C++ 函数以及如何在 mfc C++ 中调用 JavaScript 函数? [关闭]