我完全坚持这个。我的基本问题是我的:
- (NSFetchedResultsController *)fetchedResultsController
方法在尝试读取我的Core Core实体时崩溃,因为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中设置)&阻止主线程直到我收到阻止回调。
这些都不奏效。我的应用程序冻结了。我错误地想到了这个吗?如何让委托方法等到我的文档打开/准备好?或者我应该采用不同的方法吗?
由于
卡尔。
答案 0 :(得分:0)
好的,当你的应用程序第一次启动时,我会建议检查1.你的数据库是否存在(如果没有,你分配init)和2.如果文件不存在(在磁盘上),则关闭或是开放的。
这是你如何做到这一点:
看起来您正在为数据库使用单例,因此当您的第一个视图控制器出现时,请检查Managed Document是否已被分配,因此在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)已经被分配,它仍然不意味着已经在磁盘上创建了实际的数据库文件。您必须按如下方式检查它(您可以在数据库或ViewDidLoad的setter中执行此操作,但不要在另一个线程中执行此操作,因为它不起作用)
所以你在这里检查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