我的应用程序最近从仅在iOS9上发生的crashlytics中获取了这些崩溃
报告中的最后一个电话是
-[NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_device_locked:]
这就是NSPersistentStoreCoordinator的创建方式
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSURL *storeURL = [[delegate applicationDocumentsDirectory] URLByAppendingPathComponent:@"database.sqlite"];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
NSError* error = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} error:&error])
{
NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo);
return nil;
}
return _persistentStoreCoordinator;
}
有人知道是什么原因导致这些崩溃吗?
最佳答案
我没有在iOS9上遇到该错误。但是,您应该查看日志以查看存在哪些错误。创建PSC时是否可能遇到“添加持久性存储错误”?
您的方法有一个问题,如果遇到该错误,则后续调用将返回既不为零也不正确设置的PSC。
原因是您在成功设置_persistentStoreCoordinator
之前就对其进行了分配。因此,如果有任何错误,则返回nil,但是下次调用该方法时,将返回不存储的PSC。
无论如何,您都应该更改该方法,以便仅返回nil或完全运行的PSC。
我会将该方法更改为类似这样的方法。 注意,但我永远不会像这样构造核心数据栈。但是,至少以下代码可以修复您的错误,在此情况下您可以返回部分组成的PSC。
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSURL *storeURL = [[delegate applicationDocumentsDirectory]
URLByAppendingPathComponent:@"database.sqlite"];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:self.managedObjectModel];
NSError *error = nil;
if (![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:@{NSMigratePersistentStoresAutomaticallyOption:@YES,
NSInferMappingModelAutomaticallyOption:@YES}
error:&error]) {
NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo);
} else {
_persistentStoreCoordinator = psc;
}
return _persistentStoreCoordinator;
}
编辑
评论中没有足够的空间来回答您的问题,因此我在这里提出。
我发表评论是因为您发布的代码与默认的Xcode核心数据模板非常相似。您调用app-delegate来获取目录,指示该目录不在app-delegate中,这很好。
但是,该方法表明您可以从“任何地方”懒惰地访问它,这向我表明您的堆栈不是按照构建堆栈的方式构建的(特别是因为您还包括用于迁移的选项)。
我并不是要暗示您所做的事情本身就是错误的,只是那不是我要怎么做。
现在,我将是第一个说我所做的就是我所做的……而我并不是说这是正确的方式……只是我的方式。实际上,我还没有看到其他人真正做到我所做的事情(尽管我注意警告,并且远离恼火的位子,但我实际上将NSManagedObjectContext子类化)。这本身可能表明我所做的事情可能不适合您或其他任何人。但是,我发现它非常适合我,而且我必须实现非常复杂的应用程序。
那么,我将如何构建堆栈?
好吧,这值得比SO答案更深入地介绍,因此我将做简短介绍。它还取决于堆栈的类型-父/子,具有相同PSC的 sibling ,具有不同PSC但商店相同的表亲。
首先,我没有提供对模型和协调器的单独访问。您可以轻松地从上下文访问这些内容,并且通常最终会导致超出其值(value)的问题。
除了测试和简单的示例之外,我总是异步创建我的MOC,就像这样...
+ (void)createWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType
completion:(void(^)(NSManagedObjectContext *moc, NSError *error))completion;
MOM已创建并分配给PSC,PSC已创建并分配给MOC。它是异步发生的,因此可以在后台线程中完成可能耗费很长时间的打开和初始化过程。在
performBlock
中调用完成处理程序,因此可以干净地使用MOC。这也阻止了在MOC完全设置并读取运行之前使用。即使使用主队列并发类型进行调用,所有工作都在后台线程中完成,因此仅在主线程上调用完成。
当创建用于导入和临时用途的相关MOC时,我也使用相同的模式。